@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:
1 | #include <iostream> |
2 | |
3 | using namespace std; |
4 | |
5 | template <typename T> |
6 | class Templateklasse { |
7 | public:
|
8 | T eins; |
9 | T zwei; |
10 | Templateklasse(T e, T z): eins(e), zwei(z) {} |
11 | void ausgabe(void) { cout << this->eins << " " << this->zwei << endl; } |
12 | };
|
13 | |
14 | int main(int argc, char* argv[]) { |
15 | Templateklasse<int> a(1, 2); |
16 | Templateklasse<string> b("Hallo", "Welt"); |
17 | Templateklasse<1> b(1, 1); |
18 | |
19 | a.ausgabe(); |
20 | b.ausgabe(); |
21 | |
22 | return 0; |
23 | }
|
Die Klasse "Templateklasse" kann ich jetzt mit verschiedenen Datentypen verwenden, beispielsweise mit einem "int" und einem "string". Daraus erzeugt der Compiler dann eine Klasse "Templateklasse" für Integers, und eine Klasse "Templateklasse" für Strings. Die Wikipedia hat eine ganz gute Erklärung zu Templates in C++: http://de.wikipedia.org/wiki/Template_%28Programmierung%29 HTH und liebe Grüße, Karl
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
Hast du deinen Link auch mal selber gelesen? http://de.wikipedia.org/wiki/Template_%28Programmierung%29#Nichttyp-Parameter
Hallo, Karl Käfer schrieb: >
1 | > Templateklasse<1> b(1, 1); |
2 | >
|
Oh, lustig: das ist natürlich ein Fehler und wurde von mir nur in den Code geschrieben um zu sehen, ob g++ und clang++ dabei für Fehler ausgeben. Sie tun es jedenfalls. Ansonsten ist diese Zeile Unfug und zu ignorieren. Liebe Grüße, Karl
template <int pin> struct pb{ void set(){ ptr = (int*)0xDEADBEEF + pin; *ptr = 0x1; }; pb<1337> a; a.set(); Sowas ist erlaubt. Also husch nochmal paar template tutorials durcharbeiten.
:
Bearbeitet durch User
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
Karl Käfer schrieb: > Karl Käfer schrieb: >>
1 | >> Templateklasse<1> b(1, 1); |
2 | >>
|
> Ansonsten ist diese Zeile Unfug und zu ignorieren. Konstanten als Parameter sind eine grundlage der C++ Metaprogrammierung. > Nichttyp-Parameter sind > Template-Parameter, also Parameter für Templates statt für Instanzen. Sehr richtig. Und da typen keinen Speicherplaz belegen, im gegensatz zu instanzen, und man Templateclassen nicht instanzieren muss, um auf dessen statische Variablen zuzugreifen, kann man damit viel Ram und Rechenzeit sparen. C++ Metaprogramming kann ich nur emphelen: http://de.m.wikipedia.org/wiki/C%2B%2B-Metaprogrammierung Im funktionierenden Beispiel, das ich ganz weit oben mal Postete (Beide beiträge beachten), habe ich änliches gemacht. 0 bytes Overhead! Aber leider niemand, der den code kommentierte...
Daniel A. schrieb: > C++ Metaprogramming kann ich nur emphelen: Das ist wirklich cool. :-) Mache ich auch! Torsten C. schrieb: > Aber mit den diversen IDEs, die ich für µCs benutze, hat es nie > richtig funktioniert … beim Debuggen mit Breakpoints in die > Instanz-Variablen zu schauen. Aber mit welcher IDE geht das auch für µCs in der Praxis? Was nützt all Eure Theorie? Bei Visual Studio .net für Windows wäre das alles kein Problem. Aber hier geht es doch um "C++ auf einem MC", oder?
:
Bearbeitet durch User
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 | OutputPin ledPin(&DDRB, &PORTB, &PINB, PB0); |
sind DDRB, PORTB und PINB keine Variablen, also keine Instanzen, sondern Konstante. > Im funktionierenden Beispiel, das ich ganz weit oben mal Postete (Beide > beiträge beachten), habe ich änliches gemacht. 0 bytes Overhead! Aber > leider niemand, der den code kommentierte... Da schaue ich gerne hinein. Aber möchtest Du Dir vielleicht auch einmal meine Code-Beispiele in [1] und [2] anschauen? Viel Spaß! Liebe Grüße, Karl [1] Beitrag "Re: C++ auf einem MC, wie geht das?" [2] Beitrag "Re: C++ auf einem MC, wie geht das?"
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
1 | RCC_APB1PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); |
Was stimmt da nicht? Richtig, es muss heißen:
1 | RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); |
Weil ich immer wieder meine Zeit mit solchen Mist verschwende, möchte ich nun auch endlich mal 'ne ordentliche HAL-API haben. STM32CubeMX erstellt leider auch kein C++. Außerdem wird der STM32F103 noch nicht unterstützt und gerade mit dem arbeite ich hauptsächlich, weil es den bei aliexpress für weniger als 2€ gibt. Das "xpcc project" ^^ ist ja schon ziemlich dicht dran. Aber es gibt immer was, was einem nicht gefällt. Zum Beispiel könnte der USART zumindest beim TX auch den DMA-Controller nutzen, statt nur Interrupts: http://xpcc.kreatives-chaos.com/api/classxpcc_1_1stm32_1_1_usart_hal1.html Ausgezeichnet finde ich die Präsentation von Scott Meyers zu "Effective C++ in an Embedded Environment". Anbei ein Beispiel, wie man ein Peripherie-Register in c++ darstellen könnte. Auf den folgenden Slides werden viele Details besprochen und Alternativen zu dem Thema besprochen. Bei uns im Wiki gib's ja noch nicht allzuviel zu dem Thema: http://www.mikrocontroller.net/articles/Kategorie:C%2B%2B Was ich bisher so an Quellen gefunden habe, sammle ich gerade unter: https://notizblog.wordpress.com/%C2%B5c-programmierung-mit-c/ Dort ist auch ein Link zum PDF-Dokument von Scott Meyers. Hat schon jemand die Sourcen vom "xpcc project" ausprobiert? Sind diese eine gute Basis, um darauf aufzubauen? Macht es Sinn, unser gesammeltes Wissen in einem eigenen Wiki-Artikel zu sammeln?
:
Bearbeitet durch User
Torsten C. schrieb: > Macht es Sinn, unser gesammeltes Wissen in einem eigenen Wiki-Artikel zu > sammeln? Ja. Unbedingt.
[ScoMe01] Slide 169 sagt: > “A fundamental design goal is that design violations > should not compile.” Jawohl! :-) Also auch, wenn PCLK1 oder PCLK2 verwechselt werden? Oder wenn es einen Konklikt beim DMA-Kanal gibt? Torsten C. schrieb: > Zum Beispiel könnte der USART zumindest beim TX auch > den DMA-Controller nutzen, statt nur Interrupts. Ich habe daher mal ganz einfach angefangen, mit dem USART. Versteht jemand in diesem Zusammenhang diese drei Dinge?
1 | calculateBaudrateSettings (uint32_t sabclk, uint32_t baudrate) |
http://xpcc.kreatives-chaos.com/api/classxpcc_1_1stm32_1_1_uart_base.html 1. Ist "uint32_t baudrate" eine gute Idee, oder sollte das eher ein float sein? 2. Warum wird "sabclk" als Parameter übergeben und kein Pointer auf PCLK1 oder PCLK2 genutzt (rot im 2. Bild)? 3. Wie stellt man sicher, dass ein DMA-Kanal immer nur einmal verwendet wird, also z.B. SPI2_RX nicht von USART1_TX überschrieben wird? Beides zusammen geht nicht (1. Bild).
:
Bearbeitet durch User
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. :-(
:
Bearbeitet durch User
Masse könnte ich beisteuern, aber ist wohl das falsche Forum hier.
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 ;-)
:
Bearbeitet durch User
@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!
:
Bearbeitet durch User
> 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?
:
Bearbeitet durch User
was mir bisher im Internet zu dem Thema über den Weg gelaufen ist und wie dabei IO Pins angesprochen werden ... 1. Arduino pinMode(13, OUTPUT); digitalWrite(13, HIGH); digitalWrite(13, LOW); 2.) Nils Springob http://avr.2057.n7.nabble.com/template-library-for-c-td4056.html http://develissimo.com/forum/topic/8553/ typedef IOPin<system::IOPortB, 0, true> LedRed; LedRed::enable(); // set DDR bit LedRed::set(); // set PORT bit 3.) mutable-instruments avril http://mutable-instruments.net/codetools 4.) win-avr http://avr-cpp-lib.sourceforge.net/ http://sourceforge.net/projects/avr-cpp-lib/?source=typ_redirect 5.) PTL http://pfalcon-oe.blogspot.de/2013/05/peripheral-template-library-attempt-to.html board::LED::port::enable(); board::LED::output(); board::LED::high(); board::LED::low(); 6.) BOOST Ich meine in den BOOST Libs (mpl ?) ist auch etwas drin, finde es aber nicht mehr. 7.) Scott Meyers Artikel kostenlos "Effektives C++ in Embedded Systems auf Deutsch" http://www.aristeia.com/ Buch "Effective C++ in a Embedded Environment" 8.) Chris Kormanyos Buch "Real Time C++" Quellcode zum Buch: https://github.com/ckormanyos/real-time-cpp
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
Hans-Georg Lehnard schrieb: > Ist doch alles dabei ... Oops, ja, sorry. Jedenfalls sind die Templates …
1 | template< class regs, PIN pin > class DigitalInput {…}; |
2 | template< class regs, PIN pin > class DigitalInput {…}; |
besser als die vielen "#define"^^: Falls man "ins Uferlose" will, hier eine ToDo-Liste ;-) http://mikrocontroller.bplaced.net/wordpress/?page_id=744 Hans-Georg Lehnard schrieb: > Ich will keine allgemeine Library schreiben OK, vielleicht macht ja jemand anders mit. Das hatte ich falsch verstanden. Gibt es irgendwo eine geeignete Struktur, die man übernehmen sollte? Ansonsten hier eine Diskussionsgrundlage:
1 | ⊖ EmbeddedCpp |
2 | ┣⊖ Documentation |
3 | ┃ ┣⊖ General |
4 | ┃ ┃ ┣⊕ API naming rules |
5 | ┃ ┃ ┣⊕ Timeout management |
6 | ┃ ┃ ┣⊕ Error management |
7 | ┃ ┃ ┗⊕ … |
8 | ┃ ┣⊖ HAL ("µC und integrierte Peripherie") |
9 | ┃ ┃ ┣⊖ Clock |
10 | ┃ ┃ ┃ ┗⊕ … |
11 | ┃ ┃ ┣⊖ Power management |
12 | ┃ ┃ ┃ ┗⊕ … |
13 | ┃ ┃ ┣⊖ GPIOs |
14 | ┃ ┃ ┃ ┗⊕ … |
15 | ┃ ┃ ┣⊖ DMA |
16 | ┃ ┃ ┃ ┗⊕ … |
17 | ┃ ┃ ┗⊕ … |
18 | ┃ ┣⊖ APIs ("externe Peripherie") |
19 | ┃ ┃ ┣⊖ Displays |
20 | ┃ ┃ ┃ ┗⊕ … |
21 | ┃ ┃ ┣⊖ Sensors |
22 | ┃ ┃ ┃ ┗⊕ … |
23 | ┃ ┃ ┣⊖ Communication |
24 | ┃ ┃ ┃ ┣⊖ ESP8266 |
25 | ┃ ┃ ┃ ┃ ┗⊕ … |
26 | ┃ ┃ ┃ ┗⊕ … |
27 | ┃ ┃ ┗⊕ … |
28 | ┃ ┗⊕ … |
29 | ┣⊖ Sources |
30 | ┃ ┣⊖ STM32 |
31 | ┃ ┃ ┗⊕ … |
32 | ┃ ┗⊕ ATMega |
33 | ┗⊕ … |
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.
:
Bearbeitet durch User
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.
:
Bearbeitet durch User
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?
:
Bearbeitet durch User
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.
:
Bearbeitet durch User
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?
:
Bearbeitet durch User
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.
:
Bearbeitet durch User
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 ...
Matthias schrieb: > Industrial Strength C++ (Nyquist) Gibt es übrigens mittlerweile als Download beim Autor: http://sannabremo.se/nyquist/industrial/ Grüße Stefan
Hans-Georg Lehnard schrieb: > Im Anwendungscode muss dann nur das richtige Board includet werden der > eigendliche Code bleibt gleich. Genau so hätte ich es auch gern. :-) Danke! Das ist ein weiteres "fundamental design goal"! PS: Das wäre doch schon mal eine Basis für ein Projekt "µC.net C++". Wollen wir eins gemeinsames Projekt starten? Zwei "design goals" hätten wir schon, wir brauchen noch einen Namen. Da muss ich nochmal die Mods nerven => nächster Beitrag.
:
Bearbeitet durch User
Jörg Wunsch schrieb: > Für Projekte wiederum gibt es hier die Möglichkeit, einen SVN-Server > zu hosten sowie das in "Projekte & Code" zu posten. Wir haben m.E. inzwischen zwei "Design-Ziele" ^^ und könnten damit langsam starten. Vorausgesetzt, wir haben auch noch ein gemeinsames Projektziel … Eine C ++ Bibliothek mit folgenden Design-Zielen : … … brauchen wir noch einen Projekt-Namen. @Moderator: Darf der Name einen Bezug zum "mikrocontroller.net" haben, oder bedarf es da eines "Genehmigungsprozesses" oder gibt es Namensrechtliche Probleme? Der Name sollte auch als Namespace ein gültiger Bezeichner sein, hier zwei Links dazu: http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier#228797 http://www.cplusplus.com/doc/tutorial/variables/#identifiers Um mal einen Stein ins Wasser zu werfen, über den weitestgehenden Antrag muss immer zuerst abgestimmt werden: ;-) * "uCnet" als Namespace * "µC.net C++ Bibliothek" als Projektbezeichnung Es kann gern auch eine "Nummer kleiner" sein! Die Antwort ist nicht dringend, ich wollte nur, dass die Frage nicht übersehen wird. … oder ist englisch (µC.net C++ library") besser? Aber im "embdev.net/forum/" gibt's ja gar kein Forum "projects & code". Ich fände Deutsch besser. Klassen, Variablen, Funktionen sollten trotzdem in Englisch sein. Über die Sprache der Kommentare könnte man sich noch streiten. Wer will µC.net SVN und wer will github?
:
Bearbeitet durch User
@ Karl Käfer Um deinen Vergleich noch anzusprechen: ich persönlich finde
1 | DigitalOutput<PORT_B,P4> beleuchtung; |
2 | DigitalInput<PORT_B,P0> startknopf; |
etwas schöner zu verwenden als
1 | EinAus beleuchtung = EinAus(&DDRB, &PORTB, &PINB, PB2); |
2 | Eingabe startknopf = Eingabe(&DDRD, &PORTD, &PIND, PD1); |
wobei dein
1 | PINDEF(X,Y) |
das relativieren würde, sofern es funktioniert. Der output scheint ja derselbe zu sein, weswegen von dieser Seite ja nichts gegen Templates spricht.
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
Hi Micha, Micha schrieb: > wobei dein >
1 | > PINDEF(X,Y) |
2 | >
|
> das relativieren würde, sofern es funktioniert. Das funktioniert prima, probier's aus. > Der output scheint ja derselbe zu sein, weswegen von dieser Seite ja > nichts gegen Templates spricht. Aber eben auch nichts dafür. Und Templates sind, wie erwähnt, eine recht komplexe Angelegenheit, die Anfänger regelmäßig überfordert. Warum denn Komplexität einbauen, ohne Not und ohne Vorteil? Wozu Kosten und Einstiegshürden steigern, wenn kein Nutzen erkennbar ist? Das kann man machen, wenn man der einzige Nutzer ist und das aus eigenem Interesse macht. Aber bei einem Softwareprojekt, das sich auch an andere richtet, muß der Wurm dem Fisch schmecken und nicht dem Angler. Liebe Grüße, Karl
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< class regs, PIN pin > |
PIN ist ein Enum.
Karl Käfer schrieb im Beitrag #3976273:
> können wir diesen "Herrn" nicht einfach alle ignorieren?
Off-Topic (also alles was nix bringt) zu ignorieren ist eine gute Idee.
Sich beim Ignorieren an einer Person statt am Thema zu orientieren ist
keine gute Idee.
:
Bearbeitet durch User
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
:
Bearbeitet durch User
Frank M. schrieb: > Geht auch in C bei AVRs, Nur bei AVRs oder allgemeinin C? Ein C-Compiler kann doch gar keine Typsicherheit festestellen. Dem ist doch egal, zu welchem Enum-Typ ein Enumerator gehört. Ich hab mir das Thema "Registersicher" fünfmal durchgelesen und nicht verstanden, was Du meinst. Falls Du meinst, dass man das Problem mit "RCC_APB1PeriphClockCmd" ^^ auch in C (nicht C++) lösen kann, bin ich gespannt!
:
Bearbeitet durch User
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.
1 | TCCR0A |= (1 << WGM02); |
(Hint: WGM02 liegt in TCCR0B)
Torsten C. schrieb: > Nur bei AVRs oder allgemeinin C? Kannst Du natürlich auch auf andere µCs ausweichen. > Ein C-Compiler kann doch gar keine Typsicherheit festestellen. Dem ist > doch egal, zu welchem Enum-Typ ein Enumerator gehört. Ich hab mir das > Thema "Registersicher" fünfmal durchgelesen und nicht verstanden, was Du > meinst. Der Compiler stellt sicher, dass Du WGM01 ausschließlich in TCCR0A setzen kannst und nicht in einem anderen Register. Da diese Bits gerne mal von AVR zu AVR in andere Register wechseln, weil Atmel das Spaß macht, gibt/gab es schon immer dieses Problem - gerade bei der Portierung von einem µC auf einen anderen. In der klassischen Schreibweise TCCR0A |= (1<<WGM01); frisst der Compiler auch dieses: TCCR0B |= (1<<WGM01); Das ist aber ein Fehler, denn (meistens) sitzt das Bit WGM01 in TCCR0A und nicht in TCCR0B. Mit "registersicheren Bitfields" kannst Du einfach schreiben: BFM_WGM01 = 1; und Du musst überhaupt gar nicht wissen, in welchem Register das Bit überhaupt steckt. Das macht dann der Compiler. > Falls Du meinst, dass man das Problem mit "RCC_APB1PeriphClockCmd" ^^ > auch in C (nicht C++) lösen kann, bin ich gespannt! Hm, das ist eine Funktion... Da müsste es aber einen analogen Weg geben.
:
Bearbeitet durch Moderator
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!
:
Bearbeitet durch User
Torsten C. schrieb: > Wie sind denn "DDRB" und "PORTB" bei Dir definiert? … > Um sowas ^^ geht es im Satz von Scott Meyers: ^^ >> “A fundamental design goal is that design violations >> should not compile.” > Können bei Deinen "DDRB" und "PORTB" solche Verwechslungen vom Compiler > erkannt werden? Bei Templates und Enums werden sie erkannt! Darauf Karl Käfer schrieb: >> Wie sind denn "DDRB" und "PORTB" bei Dir definiert? > Wie in avr/io.h. Also mit #define und nicht mit enum! Frank M. schrieb: > Torsten C. schrieb: >> … Bei Templates und Enums werden sie erkannt! > Geht auch in C bei AVRs, Also: Typsichere enums, damit Verwechslungen vom Compiler erkannt werden, gehen auch "in C bei AVRs"^^?! Nein, aber mit C++. Das ist ja nun geklärt. Michael Reinelt schrieb: > Du verwechserst grad zwei Postings von unterschiedlichen Leuten! Sorry, falls ich was verwechselt haben sollte. Was meinst Du?
:
Bearbeitet durch User
Ich frage Karl den Käfer nochmal … … wie ich schrieb: > Waren die Antworten verständlich und überzeugend? In einem Wiki-Art… Danke fürs Aufräumen. Das hat mir viel verplemperte Zeit gespart! :-) > Beitrag #3975867 wurde von einem Moderator gelöscht. > Beitrag #3975873 wurde von einem Moderator gelöscht. > Beitrag #3976273 wurde von einem Moderator gelöscht. > Beitrag #3976354 wurde von einem Moderator gelöscht. > Beitrag #3976354 wurde von einem Moderator gelöscht. > Beitrag #3976413 wurde von einem Moderator gelöscht. > Beitrag #3976471 wurde von einem Moderator gelöscht. > Beitrag #3976507 wurde von einem Moderator gelöscht. > Beitrag #3976530 wurde von einem Moderator gelöscht. > Beitrag #3976878 wurde von einem Moderator gelöscht. > Beitrag #3976908 wurde von einem Moderator gelöscht. Um das nach den ganzen OT-Beiträgen nochmal in Erinnerung rufen: Torsten C. schrieb: > Wer will µC.net-SVN und wer will GitHub? Karl Käfer schrieb: > Torsten C. schrieb: >> * "uCnet" als Namespace >> * "µC.net C++ Bibliothek" als Projektbezeichnung > Ich würde das "net" herauslassen … Also wie genau? Nur "uC"? Neee …
:
Bearbeitet durch User
Hier wird ja zensiert was das Zeug hält. Muß echt schlimm sein EDIT durch Mod: Ist es, ist es ;-)
:
Bearbeitet durch Moderator
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...
Jürgen schrieb: > Hier wird ja zensiert was das Zeug hält. Neee, war bestimmt nur im falschen Tread "…wie geht das?" geposted: Mach einen neuen Thread auf: "… was soll das?", da wird dann vielleicht nicht zensiert. ;-) (War Spaß, gibt´s schon!) BTW: Ich habe eine "Herausforderung" (aka. "ein Problem"): Hans-Georg Lehnard schrieb: > Der g++ im Atmel Studio 6.2 kann C++11 Sytax Das passt! Ich bin ein großzügiger Patriarch ;-) (bitte Smilley beachen) und habe der Familie einen neuen "Kalender" gegönnt, siehe Beitrag "Re: Zeigt her Eure IoT Projekte" Dieser ist heute angekommen. Die Family ist zwar begeistert, aber nun ist "Heimautomatisierung" angesagt. Frank (ukw) weiß Bescheid. Es müssen per Android-Touchscreen asap. Funkschaltsteckdosen mit ESP8266 geschaltet werden! Meine Wahl fiel auf den ATTINY1634, den ich mit "Atmel Studio 6.2" wunderbar mit C++11 Sytax ^^ programmieren kann und der auch noch in der Bastelkiste liegt! :-) Was ich nun brauche sind: * ein hierarchischer Zustandasautomat und * eine C++-UART-lib. Zum UART hane ich genug Input, aber beim Zustandasautomat könntet Ihr mir helfen: Arbeitet mit Macros. Wie findet Ihr das? http://ehiti.de/machine_objects/ Nutzt boost::any. Wie findet Ihr das? http://collaboration.cmc.ec.gc.ca/science/rpn/biblio/ddj/Website/articles/CUJ/2005/0512/0512babitsky/0512babitsky.html Gefällt spontan, habe ich aber noch nicht ausprobiert: http://codereview.stackexchange.com/questions/40686/state-pattern-c-template-short-and-elegant-hierarchical-fsm-solution "switch/case" finde ich doof: http://www.eventhelix.com/realtimemantra/hierarchicalstatemachine.htm#.VL_27y4TV1A Hier werden VMTs angelegt, oder? http://accu.org/index.php/journals/252 Die Rergebnisse wären ein schönes "kick-off" für "Projekte & Code", aber ich benötige "Sparringspartner" und Tipps!
:
Bearbeitet durch User
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!
:
Bearbeitet durch User
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.
>1 startupcode >2 gpio_einlesen >3 gpio_setzen >4 adc_einlesen >5 dac_setzen >6 delay >7 pwm erzeugen >8 timer der alle X ms bestimme funktionen abarbeitet >9 uart, SPI, I²C/TWI, RS485 Bei Arduino heißt das 2: digitalRead(pinNumber) 3: digitalWrite(pinNumber,value) 4: analogRead(Channel) 5: analogWrite(Channel,value) 6: delay(ms); delayMicroseconds(us) 7: weiß nicht, gibt's aber 8: - 9: Serial.print, SPI.transfer ..
Stefan schrieb: > delay(ms); delayMicroseconds(us) Ist das Dein Ernst? Was macht der µC in der der Zeit? Einen RX-Buffer-Overflow?
:
Bearbeitet durch User
Torsten C. schrieb: > Zum UART habe ich genug Input, aber beim Zustandasautomat könntet Ihr > mir helfen… android.util.JsonReader sagt: > beginArray() / endArray() > beginObject() / endObject() > … org.xml.sax sagt: > startDocument() > startElement() / endElement() > … So ein Ereignis-gesteuertes Interface ist für µCs mit wenig RAM (512..2048 Bytes) m.E. die einzige Möglichkeit, um Daten in einem Zustandsautomaten schnell parsen zu können. Da ich über den UART http-GET und http-POST bekomme, muss ich die UART-API auch so ähnlich wie oben umsetzen. Hat jemand einen Vorschlag? Gibt's das schon? Vielleicht erfinde ich ja gerade ras Rad neu. http://en.wikipedia.org/wiki/Reinventing_the_wheel Grober Entwurf: > startLine() / endLine() > startIPD() / endIPD() > startEcho() / endEcho() … oder so ähnlich. ("IPD" = InPutData)
:
Bearbeitet durch User
hallo Bin Anfänger aber hier ist doch ein Konzept C++ OOP das sieht doch gut aus? http://avr-cpp.de/doku.php?id=grafische_programmierung_mit_der_uml gruß jan
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 | Container bag = new Suitcase(100); |
2 | bag.add(10); |
> A compiler might look at this code and determine that, when the > add method is being called, bag is of necessity a Suitcase. Thus, > it could generate code to call Suitcase's add method directly, > without reference to the VMT to which bag refers. Frage: Macht eine Bibliothek, die für mehrere Toolketten geeignet sein soll, dann überhaupt Sinn? Torsten C. schrieb: > aber beim Zustandasautomat könntet Ihr mir helfen: … > "switch/case" finde ich doof: … … denn performanter als "switch/case" ist es, wenn jeder Zustand eine Klasse (Instanz) ist oder Funktionen (function-pointer) sind! Und wir wollen in C++ ja nicht schlechter sein als in C! Daraufhin jan schrieb: > hier wird soetwas ähnliches realisiert. http://avr-cpp.de/doku.php?id=grafische_programmierung_mit_der_uml#zustaende Ein Grafischer Editor für Zustandasautomaten. Cool! Bei meinem ersten Versuch damit kam aber auch "switch/case" raus. Schade. :-( Eine Demoversion von SiSy läuft übrigens 70 Tage.
:
Bearbeitet durch User
Ich bin ja kein C++-Profi und bei mir fallen die Groschen auch nur pfennigweise. Aber weil die Frage "Wozu Templates?" vielleicht (Käfer Karl?) noch nicht hinreichend beantwortet ist: Man nutzt Vererbung ja oft, um Gemeinsamkeiten einmal in einer Basis-Klasse festzulegen. Falls dadurch VMTs entstehen (was ja nicht immer vorhersehbat ist^^), wird der C++-Code ineffizienter. Ich brauche aber höchste Effizienz (Zustandasautomat in einer ISR, s.u.)! Daher kann ich auch kein "switch/case"^^ im Zustandasautomaten gebrauchen. Mit Templates können Gemeinsamkeiten und Unterschiede aber auch ohne Vererbung definiert werden, also immer ohne VMTs, unabhängig von der Toolkette. Ist das vielleicht die Begründung, warum Templates bei Embedded C++ so wichtig sind? BTW: Das OOP Konzept "Containment" ist übrigens auch noch eine Alternative, um VMTs zu vermeiden: http://www.codeproject.com/Articles/24948/Three-Ways-To-Extend-A-Class PS zu "höchste Effizienz"^^: Ich möchte die Ansätze für die neue "µC.Cet C++-Bibliothek" auf einem ATTiny1634 erstmalig nutzen, weil ich damit gerade mein aktuelles Projekt umsetze. Der ATTiny1634 hat 1KB RAM und ich muss HTTP-Requests direkt in der ISR bearbeiten, damit ich den RX-Puffer klein halten kann. "bearbeiten" heißt dabei parsen und wie bei "JsonReader" oder "sax"^^ entsprechende Ereignisse auslösen, z.B. • NextChar(), • EndOfLine(), • NumCharsReached() oder • TimeOut(). Diese Ereignisse müssen von einem effizienten Zustandasautomaten ausgewertet werden, denn der Zustandasautomat läuft in einer ISR! PPS @Modertor: Wie sollen wir uns verhalten? Ich habe 3978837#3978829 eben gemeldet. War das gewünscht?
:
Bearbeitet durch User
Moby schrieb im Beitrag #3978856: > Am besten wie ein Mann der Widerspruch ertragen kann Mit Widerspruch habe ich kein Problem! Dass es mir um die überflüssigen > "[µC.net] Neuer Beitrag in "C++ auf einem MC, wie geht das?" geht, hatte ich ja geschrieben! 350418#3978856 und 350418#3978862 können von mir aus gelöscht werden; wenn Moby kein Gast wäre, hätte ich natürlich 'ne PN geschrieben.
:
Bearbeitet durch User
Thorsten und die Anderen, lasst euch nicht beirren von den Amöben ;-)
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.
Lars schrieb: > Torsten und die Anderen, lasst euch nicht beirren von den Amöben Ich sicher nicht. Ich antworte eher mal in einem "PS: …"
1 | class UartStreamReaderBase { |
2 | public:
|
3 | enum Event { |
4 | nextChar, |
5 | endOfLine, |
6 | numChars, |
7 | };
|
8 | |
9 | private:
|
10 | virtual void ISR_NextChar(); // ISR, die ein Ereignis auslöst, wenn ein Zeichen im RX-Puffer ist |
11 | virtual void ISR_EndOfLine(); // ISR, die ein Ereignis auslöst, wenn eine Zeilenende gefunden wurde. |
12 | virtual void ISR_NumChars(); // ISR, die ein Ereignis auslöst, wenn eine bestimmte Anzahl von Zeichen im RX-Puffer ist |
13 | // virtual void Timeout(); // Ereignis wird ausgelöst, wenn eine Zeit lang kein neues Zeichen im RX-Puffer erscheint (evt. später)
|
14 | virtual void NextChar(); // Ereignis wird von ISR_NextChar ausgelöst |
15 | virtual void EndOfLine(); // Ereignis wird von ISR_EndOfLine ausgelöst |
16 | virtual void NumCharsReached(); // Ereignis wird von ISR_NumChars ausgelöst |
17 | };
|
18 | |
19 | class Uart1StreamReader : UartStreamReaderBase { |
20 | …
|
21 | };
|
22 | |
23 | class ESP8266Webserver : Uart1StreamReader, StateMachineBase { |
24 | …
|
25 | };
|
So^^ denke ich gerade, einen Zustandsautomaten für die UART-ISR umzusetzen. Das wäre noch ohne Templates. Mal sehen, wann ich wirklich Templates brauche. PS: Moby schrieb: > war ja wohl mein Beitrag … und meinen eigenen hatte ich auch aufgeführt. Moby schrieb: > Respekt. Da hast Du Dir was vorgenommen. Gutes Gelingen. Danke. Falls Du Recht haben solltest und Embedded C++ wirklich Mist sein sollte, dann würde mir diese Erkenntnis auch nützlich sein. Aber mir ist das noch nicht klar!
:
Bearbeitet durch User
Torsten C. schrieb:
1 | class ESP8266Webserver : Uart1StreamReader, StateMachineBase {… |
PS: Ich muss mir noch den asm-Code anschauen. Falls diese Mehrfach-Vererbung eine VMT erzeugt, probiere ich mal "Containment"^^ aus. Oder kann das jemand vorhersagen?
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.
:
Bearbeitet durch User
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/
:
Bearbeitet durch User
Rolf Magnus schrieb: > Hans-Georg Lehnard schrieb: >> Du meinst Peter, hat mangels C++ Erfahrung die falsche Frage gestellt >> und eigendlich wollte er eine komplette Lib möglichst für alle >> erhältlichen MC haben ?. > > Wieso falsche Frage? > >> Das sehe ich nicht so ... > > Ich auch nicht. Das war aber auch nicht das, was ich gesagt hab. > Er wollte wissen, wie man eine C++-Bibliothek speziell für µCs macht und > wie die aussehen könnte. Genau darüber wird gerade diskutiert. Er hat > sie sich eben mangels der C++-Erfahrung vom Design her etwas anders > vorgestellt, als die jetzt diskutierten Ideen. > Seine Frage zielte auch nicht auf einen ganz spezifischen Typ ab, > sondern allgemein auf µCs. Nö, seine Frage war wie kann ich folgendes in C++ lösen bzw. wie kann ich das in C++ lernen ( in Assembler oder C schreibt er dir das im Schlaf): a. schalte Led solange Taste gedrückt b. toggle Led bei jeder (positiven) Drückflanke c. led aus wenn taster kurz gedrückt d. led an wenn taster lang gedrückt und ich füge noch dazu: e. led blinkt schnell ( 1/2 sec) wenn taster kurz (<500ms) gedrückt f. led blinkt normal(1 sec) wenn taster normal(500 ..1500ms) gedrückt g. led blink langsam(2 sec) wenn taster lang( >1500ms) gedrückt usw. Und darauf ist die Antwort: "Das kannst du mit unserer neuen uC++ Lib irgenwann mal machen" genauso gut wie 42 oder schau in die gelbe Seiten ;) Natürlich kann man alles in eine Lib verpacken. Schau dir doch mal alle bekannten Libs in dieser Richtung an, da ist keine dabei die Peters Frage konkret und nachvollziehbar beantwortet. Die Diskussion hier: wie müsste eine LIB aussehen, was müsste sie beinhalten und wie kann sie effektiv implementiert werden ist mit Sicherheit sinnvoll und nützlich aber sie beantwortet die ursprünglichen Fragen nicht. Mehr wollte ich mit meinem Post nicht sagen ... > weiterhin schrieb peda >In C wird ja für jeden Quark eine Funktion benötigt, was nicht besonders >gut lesbar ist. >In C++ könnte man Zuweisungen nehmen, wenn man nur wüßte, wie man das >implementiert. Da fragt er doch eher nach Überladung vom = operator und nicht nach einer LIB.
:
Bearbeitet durch User
Hans-Georg Lehnard schrieb: > Lieber Torsten C. du hast jetzt zwar diesen Thread erobert ;) ... Lieber Hans-Georg, der Eindruck mag entstehen und falls ich in Zukunft noch 'ne spezielle Frage zu meinen "Zustandsautomaten für die UART-ISR" ^^ habe, werde ich sie auch in einem separaten Thread stellen, denn "erobern" wollte ich den Thread nicht. Ich bleibe in Zukunft beim Zustandsautomaten für Taster! Hans-Georg Lehnard schrieb: > Und darauf ist die Antwort: > "Das kannst du mit unserer neuen uC++ Lib irgenwann mal machen" Die Diskussion um eine "neue uC++ Lib" ist ja nur Vorbereitung auf einen neuen Thread in "P&C" und behandelt - bis auf den Namen und die Liste der zu unterstützenden µC-Familien - genau auch das gefragte Thema "wie kann man 'folgendes' (effizient) in C++ lösen": Zu "Taster kurz gedrückt" und "Taster lang gedrückt" hatte Jan auf den Zustandsautomaten verwiesen: http://avr-cpp.de/lib/exe/detail.php?id=grafische_programmierung_mit_der_uml&cache=cache&media=smbutton.jpg Hier heißt das nur anders: "OnHold", "OnBtnUp" und "OnClick". Zum Thema "effizient in C++ lösen" ist meine Anmerkung (nun weiß ich ja, wie das heißt): "Compile Time Polymorphism", "Static Polymorphism" oder "Member Function Pointers" sind effizienter als "switch/case" wie bei Jans SiSy. Aber wie ich nun den Zustandsautomaten am besten umsetzen soll? Ich bin immer noch am lesen und probieren, wie ich das übersichtlich, flexibel, ohne "switch/case" und µC-tauglich ohne VMTs machen könnte. Die Antwort wird die Gleiche sein, egal ob für die UART-ISR oder für Taster.
:
Bearbeitet durch User
>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.
Ohne switch/case If/else einfach ein array von Funktionszeigern http://www.mikrocontroller.net/articles/Funktionszeiger_in_C
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.
>>Aber wie ich nun den Zustandsautomaten am besten umsetzen soll? Ich bin >>immer noch am lesen und probieren, wie ich das übersichtlich, flexibel, >>ohne "switch/case" und µC-tauglich >Ohne switch/case If/else einfach ein array von Funktionszeigern >http://www.mikrocontroller.net/articles/Funktionszeiger_in_C Meiner Meinung nach kann man die Funktiosnzeiger aber auch als versteckte Art des "goto" betrachten: http://www.thibault.org/newhome/thoughts/goto-and-fsms.html
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 ...
:
Bearbeitet durch User
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.
Moby AVR schrieb im Beitrag #3981655: > Hans-Georg Lehnard schrieb: >> Geh dich doch einfach mal bewerben... > > Der Hobbybastler ist zum Glück frei in seiner Entscheidung und kann sich > auf das wirklich notwendige beschränken. ;-) > > Zu Floskeln zähle ich Vergleiche mit Hammer, Faustkeil, Code mit > Lochstreifen einlesen usw. Hier Bitteschön der Link auf das Intel Entwicklungssystem MDS-800 mit Lochstreifenleser und Stanzer: https://docs.google.com/file/d/0B9rh9tVI0J5mRXJpSVViMGo0aGs/edit?pli=1 Und programmieren mit Dioden geht so : http://www.darrinhodges.com/wp-content/uploads/2013/09/diode_rom.png Das ist aber nicht meine Platine, die gibt es leider nicht mehr.
:
Bearbeitet durch User
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_environment Hans-Georg Lehnard schrieb: > Scott Meyers: … Effective C++ in an Embedded Environment Gut, dass ich mir nicht das "Effective C++…" [ScoMe01]^^ gekauft habe, das ist zu 90% das Gleiche! Die Templates gefallen mir grundsätzlich, weil sie so klar gegliedert sind, also leicht zu verstehen und zu pflegen. Ich hatte sie schom mal gesehen, aber irgendwie sind sie in Vergessenheit geraten. Danke für den Hinweis! Mich würde mal interessieren, wie der Code nach einer "template expansion" aussieht. Dann hätte Käfer Karl auch 'ne variante ohne Templates. ;-) Mit "-fdump-rtl-all" kann man ja schon etwas davon sehen, ist aber unübersichtlich. Vielleicht kennt jemand was besseres dafür? Hans-Georg Lehnard schrieb: > http://www.boost.org/doc/libs/1_55_0/libs/msm/doc/HTML/ch03s02.html Ob die BOOST-Version wohl ohne new(), also ohne dynamic memory allocation auskommt? Gerade das finde ich beim AVR nämlich gut: Normalerweise hat der gar keine new()-Operator: http://www.avrfreaks.net/forum/avr-c-micro-how?name=PNphpBB2&file=viewtopic&t=59453 jan schrieb: > Ohne switch/case If/else einfach ein array von Funktionszeiger in C Genau, weil´s schneller geht als mit enums. Die nächste Funktion ist ja schon klar, wenn man die int-Variable "state" auf den nächsten Wert setzt. Warum soll man dann später nochmal ein "switch (state)" mit einem Haufen case-Anweisungen bauen??? Ich habe es nach viel Schweissarbeit endlich geschafft, einen kleinen Zustandsautomaten sogar mit Typ-Sicheren Funktionszeigern (Delegates) zu implementieren, ohne Templates, erstmal noch "geradeaus": Das ist Option 4: pointer to member functions (fastest solution) aus: http://stackoverflow.com/questions/9568150/what-is-a-c-delegate Es gibt drei Zeiger-Typen:
1 | /***********
|
2 | * SM_RX_ISRs
|
3 | ************/
|
4 | struct SM_OkEvents { |
5 | void SM_noInitRestetOnOK(); |
6 | };
|
7 | typedef void(SM_OkEvents::*SM_OkEvent)(void); |
8 | SM_OkEvents sM_OkEvents; |
9 | SM_OkEvent onOKEvent = &SM_OkEvents::SM_noInitRestetOnOK; |
10 | /*************
|
11 | * SM_ErrEvents
|
12 | **************/
|
13 | struct SM_ErrEvents { |
14 | void SM_TrapOnError(){TrapCPU();}; |
15 | void SM_noInitEntry(); |
16 | };
|
17 | typedef void(SM_ErrEvents::*SM_ErrEvent)(void); |
18 | SM_ErrEvents sM_ErrEvents; |
19 | SM_ErrEvent onErrorEvent = &SM_ErrEvents::SM_TrapOnError; |
20 | /***********
|
21 | * SM_RX_ISRs
|
22 | ************/
|
23 | struct SM_RX_ISRs { |
24 | void ESP_USART_RXdefault_ISR(){TrapCPU();}; |
25 | void ESP_USART_FindMagic_ISR(); |
26 | void ESP_USART_EatChars_ISR(); |
27 | };
|
28 | typedef void(SM_RX_ISRs::*SM_RX_ISR)(void); |
29 | SM_RX_ISRs sM_RX_ISRs; |
30 | SM_RX_ISR USART_RX_ISR = &SM_RX_ISRs::ESP_USART_RXdefault_ISR; |
Die "SM_RX_ISRs" sind verschiedene ISRs für den "USART0_RX_vect", also so:
1 | ISR(USART0_RX_vect) { |
2 | // vectors are located in flash rom
|
3 | (sM_RX_ISRs.*USART_RX_ISR)(); |
4 | // TODO: In ASM würde man nur springen und würde den Funktionsaufruf vermeiden.
|
5 | }
|
Und der Zustandsautomat (kleiner Web-Server), reagiert nur auf diese Interrupps und löst je nach eintretender Bedingung ein "SM_ErrEvent" oder ein "SM_OkEvent" aus, um damit den nächsten Zustandsübergang zu erreichen. Da die Ereignisse (ohne swich/case/…) sehr schnell bearbeitet werden, kann der Automat hoffentlich komplett in der ISR laufen. Hans-Georg Lehnard schrieb: > mein Post war ja auch mit einem Augenzwinkern versehen ... Hab´ ich gesehen, alles im grünen Bereich! Aber ich muss mal meckern: Es nervt, wenn man hier im Thread mal was sucht und zwischen den ganzen "lustigen" Posts nix wieder findet ("da war doch mal ..."). Bald sind wir auf Seite 3 und dann geht das Hin-und-her-Geblättere los. "Es lebte einst ein kleiner Moby in seiner Assembler Welt …" usw. war zwar ganz lustig, aber vielleicht kannst auch Du versuchen, den Thread übersichtlicher zu halten.
:
Bearbeitet durch User
chris_ schrieb: > Allerdings könnte die "goto" Variante tatsächlich die schnellste sein. chris_ schrieb: > Meiner Meinung nach kann man die Funktiosnzeiger aber auch als > versteckte Art des "goto" betrachten: Was Du immer mit Deinem GoTo willst, musst Du mir mal erklären! Torsten C. schrieb: > Warum soll man dann später nochmal ein "switch (state)" mit einem Haufen > case-Anweisungen bauen??? Mit "später nochmal" meine ich: Irgendwann, wenn das nächste Ereignis (Spalte "Event") eintritt. Dann wird halt ggf. nach der "Guard" geschaut, eine "Action" ausgeführt und der Zeiger auf eine Tabelle mit denjenigen Reihen ("a_row/_row") gesetzt, deren "Start" in der "Target" stehen. Du hast dann pro Zustand eine Unter-Tabelle mit je einem Funktionszeiger in C pro Event. Wo ist da Dein GoTo?
:
Bearbeitet durch User
>Wo ist da Dein GoTo? Dein Bild hast du ja schon von der richtigen Seite kopiert. 3.ter Codeblock: http://www.crystalclearsoftware.com/soc/coroutine/coroutine/finite_state_machines.html
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.
Theoretiker schrieb: > Ein "verstecktes" Goto ist nicht schlimm. Auch ein offensichtliches, explizites Goto ist nicht schlimm.
chris_ schrieb: > 3.ter Codeblock: Ach mit "yield", das kannte ich bis eben noch gar nicht: http://www.cplusplus.com/reference/thread/this_thread/yield/ OK, bei Multi-Threading kann man das auch mit GoTo machen, nun habe ich es verstanden. Aber ob das auf einem µC Sinn macht? Interessante Fragestellung! Falls ja, Multi-Threading wäre 'ne feine Sache und ein echter Pluspunkt für die Einfachheit der Programmierung, gerade bei Zustandsautomaten. Aus Erfahrung mit Multi-Threading-Programmierung mit C# unter Windows kann ich jedoch berichten, dass sich solche Programme manchmal schwer debuggen lassen.
:
Bearbeitet durch User
Hans-Georg Lehnard schrieb: > Der einzige Glaubenskrieger hier ist Moby. Man sollte die Dinge möglichst einfach halten. Das Motto "Keep it simple" ist keine Glaubensfrage , sondern eine Gebot rationaler Vernunft. Oder wie sagte schon der große Karl der Käfer: "Warum denn Komplexität einbauen, ohne Not und ohne Vorteil? Wozu Kosten und Einstiegshürden steigern wenn kein Nutzen erkennbar?"
:
Bearbeitet durch User
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.
:
Bearbeitet durch Moderator
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.
:
Bearbeitet durch User
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.
:
Bearbeitet durch Moderator
Eigentlich geht die ganze Diskussion, mal von Moby abgesehen, nur um das, was Arduino macht. Dahinter verbirgt sich C++.
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?
:
Bearbeitet durch User
Hallo Thorsten, ich verstehe nicht wo jetzt das new() herkommt. Objekte kann man doch auch statisch anlegen. Auch hier wird ein/einer der CTors/DTors ausgefühert, entweder implizit (z.b. der StandardKonstruktor) oder explizit.
1 | class MyObject |
2 | {
|
3 | // MyStuff
|
4 | MyObject (Paramter, liste); |
5 | }
|
6 | |
7 | MyObject obj1(Parameter des CTor); |
Kannst Du mir erklären wo ich gerade hänge ?
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
:
Bearbeitet durch User
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 | virtual void set()=0; |
6 | virtual void reset()=0; |
7 | virtual bool read()=0; |
8 | }
|
9 | |
10 | class
|
11 | GpioA0 : public AbstractGpio |
12 | {
|
13 | public:
|
14 | GpioA0(...) { ... } |
15 | |
16 | void set() { GPIOA->BSRRL = (1<<0); } |
17 | void reset() { GPIOA->BSRRH = (1<<0); } |
18 | bool read() { return GPIOA->IDR & (1<<0); } |
19 | }
|
Dann kann man einer Klasse, welche Pins benutzen muss, Pointer auf AbstractGpio Instanzen übergeben und darüber die Pins ansprechen. Also der Standard Laufzeitpolymorphismus.
1 | class
|
2 | SopftwareI2C
|
3 | {
|
4 | SopftwareI2C(AbstractGpio* Scl, AbstractGpio* Sda, ...) {...} |
5 | }
|
6 | |
7 | SopftwareI2C i2c(&gpioA0Instance, &gpioA1Instance); |
Hierbei wird aber jegliches Inlinen durch den Compiler verhindert (denn die Bindung Pin zu Klasse findet ja erst zur Laufzeit statt) und ausserdem v-tables erzeugt. D.h. es gib einen Overhead. Dieser wird durch den oben erwähnten Compilezeit Polymorphismus verhindert. Mit dem Nachteil, dass beim Compilezeit Polymorphismus nur statische Konstrukte unterstützt werden. Mit einer Laufzeitpolymorphismus Lösung kann man dagegen die Pins während der Laufzeit wechseln.
1 | i2c.setScl(&gpioB0Instance); |
Das ist nichts was man normalerweise auf einem Mikrocontroller machen möchte, aber doch ein Feature, dass manche User, die von der PC Programmierung her kommen erwarten und das z.B. bei Arduino mit der Adressierung von Pins über Integer realisiert wird. eKiwi PS: Natürlich kann man, statt für jeden Gpio eine eigene Klasse anzulegen, das ganze, wie weiter oben in diesem Thread schon erwähnt wurde, mit Hilfe von Template lösen. Ich habe das aber hier nicht beachtet, damit die Beispiele einfacher werden. Nur weil xpcc die Gpio Klassen mit jinja2 Templates erzeugt, heist das nicht, dass es der beste Weg ist. C++ Templates haben unter anderem den Vorteil, dass sie keine grossen Anforderungen an die Buildumgebung stellen. [0] Für diejenigen, die es interessiert ein paar Details am Beispiel des stm32f407vg: 1. Für unsere unterstützten Controller gibt es eine XML Beschreibung z.B.: https://github.com/roboterclubaachen/xpcc/blob/develop/src/xpcc/architecture/platform/devices/stm32/stm32f405_407_415_417-i_r_v_z-e_g.xml 2. Mit deren Hilfe werden für jeden verfügbaren (also auch gebondeten) Pin drei Klassen erzeugt: z.B. GpioA0, GpioOutputA0, GpioInputA0 Das Headerfiletemplate (jinja2) dazu sieht so aus: https://github.com/roboterclubaachen/xpcc/blob/develop/src/xpcc/architecture/platform/driver/gpio/stm32/gpio.hpp.in [1] Als Beispiel eignet sich unser Software I2C Treiber: https://github.com/roboterclubaachen/xpcc/blob/develop/src/xpcc/architecture/platform/driver/i2c/generic/i2c_master.hpp
@Scelumbro: Habe ich zu spät gemerkt, sorry, danke. Es zwei da zwei unterschiedliche Ansätze. Bei dem Code von Peter L. kommt "kaum mehr als als ein einzige Assemblerinstruktion"^^ raus, wenn set() als "inline" optimiert wird. Ob es was bringen würde, set() in die .h als "inline set() {… zu schreiben, ist ein separates Thema, kommt später! ^^ Das wäre der eine Ansatz. Aber es gibt sicherlich auch komplexere Funktionen, die für die Beantwortung der Ausgangfrage erforderlich sind, bei denen "inline" wohl keinen Sinn mehr macht:
1 | LED2.on = KEY2.press_long; // lang drücken - an |
Hier gibt es ja z.B. kein
1 | KEY2.setLongPressTime(); |
Als ich eben schrieb: "Das Port-Register z.B. soll ja als const definiert sein", hatte ich ein schlechtes Beispiel. Vielleicht ist die LongPressTime ein besseres. Angenommen, die longPressTime soll zur Compilezeit bereits feststehen. Die "longPressTime "sollte in diesem Fall doch im ROM stehen, oder? Würde man dem OP für 3 Tasten mit unterschiedlichen Zeiten (5s/6s/7s) empfehlen, dass er per Template 3 verschiedene Klassen erzeugt, also:
1 | LPKey<5,1337> key1; |
2 | LPKey<6,1338> key2; |
3 | LPKey<7,1339> key3; |
Und der Timer, der jeweils benutzt werden soll, muss ja auch parametrierbar sein, also => ein weiterer Template-Parameter. Wer weiss, was noch alles dazu kommt! Das gibt einen Haufen Templates für Karl den Käfer ;-) Irgendwann kommt man an den Punkt, wo man einen Parameter gern als Objekt-Eigenschaft definieren würde Als const (so, wie oben):…
1 | MyObject obj1(Parameter des CTor); |
… geht das aber nicht, und damit steht die Zahl dann im RAM und wird zur Laufzeit ständig dynamisch ausgelesen, wenn man sich nicht auf die Compiler-Optimierung verlassen will. Aber vielleicht machen const Eigenschaften auch keinen Sinn und man muss - wenn man den Parameter nicht als Template-Parameter übergibt - halt damit leben, dass der Parameter zur Laufzeit bei jedem Funktionsaufruf ausgewertet wird. Frank M. schrieb: > Generic Methods (vergleichbar mit C++-Templates) gibts auch in Java ;-) Das war anders gemeint: Wenn z.B. die "LongPressTime" zur Compilezeit bereits fest steht, ist ein setLongPressTime() kontraproduktiv. In Java habe ich mir über "ROMable" nie Gedanken gemacht, das ist da auch unüblich und das Thema ist für mich Neuland.
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.
:
Bearbeitet durch User
Hallo eKiwi, Deine Antwort sehe ich erst jetzt, sehr gute Erklärung! :-) eKiwi schrieb: > Wenn nun also für jeden Gpio eine Instanz erstellt wird, dann wäre der > "normale" Ansatz eine Gpio Basisklasse mit als "virtual" deklarierten > Funktionen anzulegen Beim GPIO habe ich ein blödes Beispiel gewählt. Die longPressTime ist hoffentlich besser: Warum virtual? Da sitzt genau mein Klemmer: Wenn sich nur die Daten unterscheiden, aber die Funktionen immer gleich sind, müssen die Funktionen doch nicht virtuell sein. Trotzdem sollen die Daten im ROM liegen. Wahrscheinlich ist das ganz einfach und ich habe Tomaten auf den Augen. eKiwi schrieb: > Natürlich kann man, statt für jeden Gpio eine eigene Klasse > anzulegen, das ganze, wie weiter oben in diesem Thread schon erwähnt > wurde, mit Hilfe von Template lösen. So "Natürlich" war das bis eben für mich nicht, aber dann scheint das wohl der einzige gangbare Weg für "enbedded" zu sein, um "vergessen von configure()…"^^ usw. zur Compilezeit zu detektieren.
:
Bearbeitet durch User
Hans-Georg Lehnard schrieb: > Das Template ist überflüssig, du kannst Pin gleich als Parameter > übergeben. Als Parameter an wen? Aktuell als Parameter an das Template. Das ist bis auf vergessene volatile und den Umweg über ptr* doch ganz nett für inline. Meinst Du vielleicht als Parameter an einen constructor (ctor)? Dann wären wir wieder bei einer Instanz (also nicht static). Wäre der ptr dann noch ROMable? Ich wüsste nicht, wie.
:
Bearbeitet durch User
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. :-)
:
Bearbeitet durch User
Torsten C. schrieb: > Beim GPIO habe ich ein blödes Beispiel gewählt. Die longPressTime ist > hoffentlich besser: Naja, das ganze sind doch erst einmal verschiedene Baustellen: Bei den Gpios will man für jeden eine eigene Klasse haben, da eben nicht die Daten sondern der zu erzeugende Code unterschiedlich ist. Also zumindest wenn man das so wie oben z.B. von Micha erwähnt wurde macht. Das hat den Vorteil, dass eine Instanz der Klasse keine Daten enthält und daher praktisch eine Grösse von 0 hat. Micha schrieb: > @ Karl Käfer > Um deinen Vergleich noch anzusprechen: ich persönlich > findeDigitalOutput<PORT_B,P4> beleuchtung; > DigitalInput<PORT_B,P0> startknopf; Zugegeben hatte ich die Loesung von Karl vergessen: Karl Käfer schrieb: > #include <avr/io.h> > > class Pin { > public: > volatile uint8_t* ddr; > volatile uint8_t* port; > volatile uint8_t* pin; > uint8_t num; > > Pin(volatile uint8_t* ddr, volatile uint8_t* port, > volatile uint8_t* pin, uint8_t num): > ddr(ddr), port(port), pin(pin), num(num) > {} > }; > > class InputPin : public Pin { > public: > InputPin(volatile uint8_t* ddr, volatile uint8_t* port, > volatile uint8_t* pin, uint8_t num): > Pin(ddr, port, pin, num) { > *this->ddr &= ~(1 << this->num); > } > int isHigh(void) { return (*this->pin & (1 << this->num)); }; > int isLow(void) { return !((*this->pin & (1 << this->num))); }; > }; > > class OutputPin : public Pin { > public: > OutputPin(volatile uint8_t* ddr, volatile uint8_t* port, > volatile uint8_t* pin, uint8_t num): > Pin(ddr, port, pin, num) { > *this->ddr |= (1 << this->num); > } > void setHigh(void) { *this->port |= (1 << this->num); }; > void setLow(void) { *this->port &= ~(1 << this->num); }; > void operator=(bool const &parm) { > if(parm) { this->setHigh(); } > else { this->setLow(); } > } > }; > > int main(void) { > > OutputPin ledPin (&DDRD, &PORTD, &PIND, PD0); > InputPin btnPin (&DDRB, &PORTB, &PINB, PB0); > > while(1) { > //... > ledPin.setHigh(); > ledPin.setLow(); > ledPin = btnPin.isHigh(); > } > } Hier hast du wirklich eine Pin Klasse, bei der die Instanzen jeweils andere Daten erhalten. Hierauf treffen dann meine oben gemachten Kommentare nicht ganz zu. Mich würde aber noch interessieren wie weit man das ganze treiben kann, bis der Compiler Speicherplatz für ddr, port, pin und num anlegt. An sich aber auf jeden Fall ein interessanter Ansatz. > Warum virtual? Da sitzt genau mein Klemmer: > > Wenn sich nur die Daten unterscheiden, aber die Funktionen immer gleich > sind, müssen die Funktionen doch nicht virtuell sein. Genau. Aber spätestens wenn du eine Funktion hast, die nicht direkt einen Pointer auf einen Pin benutzt, sondern einen Pointer, der ein Member der Klasse, zu der diese Methode gehört, ist, dann wird - nach meinem Verständnis - doch Speicher für die Datenmember des Pins angelegt werden muessen, da zur Compilezeit nicht bekannt ist, welcher Pin genau angesprochen wird. z.B.
1 | class
|
2 | SoftwareI2C
|
3 | {
|
4 | public:
|
5 | SoftwareI2C(Pin* Scl, Pin* Sda) : scl(Scl), sda(Sda) {} |
6 | |
7 | void run() |
8 | {
|
9 | // hier ist voraussichtlich zur Compilezeit nicht bekannt,
|
10 | // welcher pin das ist, also kann das nicht in einen simplen
|
11 | // ASM Befehl übersetzt werden
|
12 | // wahrscheinlich wird das eine function call an die Pin::set
|
13 | // Methode mit der Adresse in this->scl als Argument erzeugen
|
14 | // wobei in dieser Methode dann aus den Daten an dieser Adresse
|
15 | // das Register berechnet wird
|
16 | // an dieser Stelle sollte man sich aber wohl wirklich
|
17 | // mal den ASM Code ansehen
|
18 | // vielleicht habt ihr ja etwas cooles gefunden und das
|
19 | // ganze wird wegoptimiert (da gcc schlauer ist als ich denke)
|
20 | this->scl->set(); |
21 | }
|
22 | |
23 | private:
|
24 | Pin* scl; |
25 | Pin* sda; |
26 | |
27 | }
|
> Trotzdem sollen die Daten im ROM liegen. Wahrscheinlich ist das ganz > einfach und ich habe Tomaten auf den Augen. Dazu kann ich die bereits oben zitierten Folien empfehlen, dort steht ganz gut, wann etwas ins ROM kommt und wann nicht: http://aristeia.com/TalkNotes/C++_Embedded_Deutsch.pdf
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.html Torsten C. schrieb: > Wäre der ptr dann noch ROMable? Ich wüsste nicht, wie. Nun weiss ich wie! Das geht per constexpr wunderbar. Ich hab's gerade mit avr GCC 4.7.2 probiert. Das löst meinen Knoten im Kopf! :-) Alex Allain sagt dort: > In fact, the only compiler version I know of that fully > supports constexpr is GCC 4.7. Hmmm, die Aussage ist doch hoffentlich schon etwas älter, oder? eKiwi schrieb: > Ralf G. schrieb: >> Ich habe >> allerdings noch keinen Einfall, wie man solche Objekte universell in >> andere Objekte einbinden kann (ohne diese <>-Klammerlisten). > > Wenn man universelle Klassen schreiben möchte muss man sich dann, früher > oder später zwischen Lauf- und Compilezeitpolymorphismus (aka das Ding > mit den <>-Klammerlisten) entscheiden. Mit constexpr ist m.E. auch die Variante von Karl Käfer ROMable. Zur Frage, ob der Compiler Speicherplatz für ddr, port, pin und num anlegt. Bei
1 | const uint8_t num; |
sicherlich nicht. Die Eigenschaften ddr, port und pin kann man doch sicher auch const machen. Nun habe ich nur noch ein Problem mit Instanzen statt Templates: Kann man irgendwie verhindern, dass ein Pin doppelt instanziiert wird? Ich kenne dafür nur Singletons. Sollte man versuchen, Singletons umzusetzen?
:
Bearbeitet durch User
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.
:
Bearbeitet durch User
Torsten C. schrieb: > > Nun weiss ich wie! Das geht per constexpr wunderbar. Ich hab's gerade > mit avr GCC 4.7.2 probiert. Das löst meinen Knoten im Kopf! :-) > > Alex Allain sagt dort: >> In fact, the only compiler version I know of that fully >> supports constexpr is GCC 4.7. > > Hmmm, die Aussage ist doch hoffentlich schon etwas älter, oder? > Der Aktuelle Compiler im Atmel bei mir (4.8.1) ist nicht 100% C++11 kompatibel. Vor allen Dingen die C++11 Libs fehlen. Bisher ist mir nur aufgefallen, das "auto" mit Vorsicht zu geniessen ist. > Mit constexpr ist m.E. auch die Variante von Karl Käfer ROMable. Zur > Frage, ob der Compiler Speicherplatz für ddr, port, pin und num anlegt. > Bei >
1 | const uint8_t num; |
> sicherlich nicht. Die Eigenschaften ddr, port und pin kann man doch > sicher auch const machen. Nochmal: ddr, port, pin usw. müssen Ram Speicher haben sonst könnte man ja nichts ändern! Aber den gibt es schon im SFR Bereich vom Ram, du must es dem Compiler nur erzählen. > Nun habe ich nur noch ein Problem mit Instanzen statt Templates: Der Begriff Instanz ist hier mehrdeutig. Templates werden immer instanziiert, leben aber nur im (PC)Arbeitsspeicher vom (Cross)Compiler. Das was du meinst sind Objektinstanzen einer Klasse die während der Laufzeit im Speicher vom Target MC leben. > Kann man irgendwie verhindern, dass ein Pin doppelt instanziiert wird? Wenn die erste (template) Instanz für den Compiler konstant ist und die 2. versucht diese Konstante zu überschreiben sollte er eine Fehlermeldung bringen. Hab ich aber noch nicht probiert. > Ich kenne dafür nur Singletons. Ja, ja die kleine wunderbare Welt der Java Programmierer ;) ich hatte mal das Verknügen meinen Java Kollegen Thread Synchronisierung bei zu bringen ... Braucht man doch bei Java alles nicht hör ich gerade ... Aber nur wenn alle Threads in der gleichen VM leben. Ein Embedded Programierer würde dafür eher pro Port ein Byte reservieren und dort ein Bit für jeden belegten Pin setzen.
Hans-Georg Lehnard schrieb: > Das was du meinst sind Objektinstanzen einer Klasse die während der > Laufzeit im Speicher vom Target MC leben. Genau, aber mein Problem^^ ist, wie man bei dieser Art der Modellierung eine doppelte instanziierung vermeiden kann. Ansonsten finde ich den Ansatz von Karl Käfer erstmal optimal. Mal sehen, was die Praxis sagt. Im o.g. Port-Beispiel ist das vielleicht nicht so schlimm. Aber zwei RingBuffer auf einen und den selben UART wären z.B. doof. Hans-Georg Lehnard schrieb: > Nochmal: ddr, port, pin usw. müssen Ram Speicher haben sonst könnte man > ja nichts ändern! Ach. Aber die Adressen (Zeiger!!) ddr, port und pin sollen doch konstant also ROMable sein und nicht im RAM liegen. Oder? Nix ändern können fände ich doof. ;-) :-p
1 | volatile uint8_t* ddr; |
2 | volatile uint8_t* port; |
3 | volatile uint8_t* pin; |
Warum eigentlich drei getrennte Pointer? Einen einzigen fände ich übersichtlicher. Ich bin gerade mit dem UART am basteln, da reicht ein ein einziger USART_t*:
1 | typedef struct { |
2 | volatile uint8_t udr; |
3 | union { |
4 | volatile uint16_t word; |
5 | struct { |
6 | volatile uint8_t low; |
7 | volatile uint8_t high; |
8 | } byte; |
9 | } ubrr; |
10 | volatile uint8_t ucsrd; |
11 | volatile uint8_t ucsrc; |
12 | volatile uint8_t ucsrb; |
13 | volatile uint8_t ucsra; |
14 | } USART_t; |
:
Bearbeitet durch User
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 | class Pin { |
2 | public:
|
3 | volatile uint8_t* ddr; |
4 | volatile uint8_t* port; |
5 | volatile uint8_t* pin; |
6 | uint8_t num; |
7 | };
|
Also kann auch mal jemand schreiben, dass sich das während der Laufzeit ändert:
1 | Pin ichbinmaldiesmaldas(ddr, port, pin, num); |
2 | ichbinmaldiesmaldas.port = &einanderer; // ??? |
Ich meine, die Pointer müssen konstant sein, damit der Compiler da wirklich zuverlässig z.B. "sbi 0x17, 3" draus macht und nicht nur zufällig je nach Compiler-Optimizing-Level. Aber vielleicht weiss es jemand besser? Ich lerne gern dazu! Also, falls ein "const" nötig ist, ich musste gerade selber mal googeln: Bradley Jones sagt:
1 | const char * myPtr = &char_A; // pointer to a constant character. You cannot use this pointer to change the value being pointed to |
2 | char * const myPtr = &char_A; // constant pointer to a character. The location stored in the pointer cannot change |
3 | const char * const myPtr = &char_A; // pointer to a character where both the pointer value and the value being pointed at will not change. |
http://www.codeguru.com/cpp/cpp/cpp_mfc/general/article.php/c6967/Constant-Pointers-and-Pointers-to-Constants.htm Das vergesse ich immer wieder. :-( Ich habe meinen uart gerade compiliert und zumindest hatte der Compiler nix zu meckern:
1 | class Uart { |
2 | private:
|
3 | static const int SFR_OFFSET = 0x20; |
4 | public:
|
5 | enum UartPtr { |
6 | Uart0 = SFR_OFFSET + 0x20, // statt #define UDR0 _SFR_IO8(0x20) |
7 | Uart1 = SFR_OFFSET + 0x73 // statt #define UDR1 _SFR_IO8(0x73) |
8 | };
|
9 | Uart(UartPtr UartPtr) : registers((USART_t *) UartPtr) {} |
10 | private:
|
11 | USART_t * const registers; |
12 | };
|
:
Bearbeitet durch User
Torsten C. schrieb: > Ich meine, die Pointer müssen konstant sein, damit der Compiler da > wirklich z.B. "sbi 0x17, 3" draus macht, aber vielleicht weiss es > jemand besser? Ich lerne gern dazu! - Die Pointer müssen nicht konstant sein! - DDRx, PORTx, PINx sind keine Pointer - man kann einen Zeiger darauf definieren - wenn der Compiler die Chance hat zu erkennen, dass dieser Pointer immer nur auf eine Adresse zeigt, dann optimiert er das! - Wenn ein Pointer auf verschiedene Objekte 'gestellt' wird, kann der Compiler selbstverständlich nicht optimieren, weil im 'sbi'-Befehl die Adresse direkt codiert ist. - ...
:
Bearbeitet durch User
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?
:
Bearbeitet durch User
Torsten C. schrieb: > eKiwi schrieb:class Pin { > public: > volatile uint8_t* ddr; … PS: Da habe ich eine Zeile verschluckt. Den Vorschlag hat zwar eKiwi zitiert, aber er kommt von Karl Käfer aus Beitrag #3902529. Sorry. Vorteil des Vorschlags: * Ohne diese <>-Klammerlisten^^
:
Bearbeitet durch User
Torsten C. schrieb: > Also kann auch mal jemand schreiben, dass sich das während der Laufzeit > ändert: >
1 | Pin ichbinmaldiesmaldas(ddr, port, pin, num); |
2 | > ichbinmaldiesmaldas.port = &einanderer; // ??? |
>
Prinipiell hast du recht und das musst du verhindern. C++ erzeugt bei
Klassen automatisch einen Copy Constructor und einen Destructor.
Die beiden sollte man "leer" überschreiben und als privat deklarieren
dann ist das sicher.
Und vergiss nicht von allem was C++ kann ist nur ein Teil für die
embedded Programmierung geeignet sonst hast du deinen mühsam gespaarten
Speicher schnell, durch eine lib die automatisch dazugelinkt wird,
wieder zunichte gemacht.
Sorry .. das ist ja ein gnu Linker und der linkt natürlich nicht dazu
sondern dagegen ;)
:
Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.