Forum: Compiler & IDEs C++ Klassenbibliothek für AVR


von Daniel W. (danielwidmann)


Lesenswert?

Hallo,
kennt jemand eine Klassenbibliothek, die den Zugriff auf die Hardware 
von AVRs über Objekte ermöglicht?

Gruss Daniel Widmann

:
von incunabulum (Gast)


Lesenswert?

Frage: Warum willst du dies machen?

Ich verwende zwar auch Klassen für Ringbuffer etc, aber die AVR Hardware 
wird ganz klassisch in C geschrieben, da ich hier von Vererbung, 
Mehrfachinstanzen etc. keine Vorteile habe, imho. Vom erhöhten 
Speicherplatzbedarf und der zur Zeit noch vorhandenen Problematik, dass 
immer alle (!) Methoden einer verwendeten Klasse - ob nun genutzt oder 
nicht - gelinkt werden, zu schweigen.

cu, mz

von Frank J. (frajo)


Lesenswert?


von Daniel W. (danielwidmann)


Lesenswert?

@frajo:
Danke für den link

@incunabulum:
Ich denke auch ohne Mehrfachinstanzen, dynamisch erzeugte Objekte, etc. 
lässt sich c++ Sinnvoll einsetzen. Das mit dem erhöhten Speicherbedarf 
ist meiner Meinung nach Irrglaube. Wenn man dynamisch Objekte erzeugt 
oder Polymorphie verwendet, wird sicherlich sehr viel Speicher benötigt. 
Aber man kann ja z.B. staische Funktion verwenden, da muss man keine 
Instanzen erzeugen. Oder mit Hilfe von inline Funktionen kann man 
verhindern, dass nicht benötigte Methoden gelinkt werden.
Wie Frank das richtig erkannt hat, suche ich einen HAL für den AVR. Ein 
HAL wäre der erste Schritt um von den Vorteilen der Objekt-Orientierten 
Programmierung profietieren zu können. Besonders der die 
wiederverwendbarkeit von Code wird dadurch vereinfacht.

Gruss Daniel

von Andreas K. (a-k)


Lesenswert?

Erfahrungsgemäss ist die einzige gut und einfach verwendbare C++ 
Classlib die selbst geschriebene. Jede andere nervt durch Bugs und 
fehlende oder irreführende Doku.

von Rolf Magnus (Gast)


Lesenswert?

> da ich hier von Vererbung, Mehrfachinstanzen etc. keine Vorteile habe,

Es gibt auch andere nützliche C++-Features. Man muß nicht gleich alles 
nutzen, was die Sprache hergibt, um sie sinnvoll einsetzen zu können. 
Vererbung kann allerdings meiner Meinung nach schon ab und zu sinnvoll 
sein. Leider ist das mit g++ auf AVR aber alles andere als optimal 
implementiert, da die vtables immer im RAM gespeichert werden, was 
eigentlich unnötig ist.
Mal abgesehen davon:  Vor allem mit Templates und Operatorüberladung 
läßt sich schon sehr viel Nützliches machen, z.B. eine Art Smartpointer 
auf Flash, der beim Dereferenzieren automatisch pgm_read_* aufruft, eine 
Festkomma-Klasse, die sich fast wie ein eingebauter Datentyp verhält 
oder ein I/O-Bit-Typ, der ein einzelnes Bit in einem I/O-Register 
bedient und der zuweisungskompatibel zu bool ist.

> imho. Vom erhöhten Speicherplatzbedarf und der zur Zeit noch

Der Speicherbedarf ist nur dann höher, wenn man nicht aufpaßt. Er kann 
sogar niedriger sein.

> vorhandenen Problematik, dass immer alle (!) Methoden einer verwendeten
> Klasse - ob nun genutzt oder nicht - gelinkt werden, zu schweigen.

Sicher? Der Linker hat eigentlich keine Ahnung, ob der Code C oder C++ 
ist und sollte sich dementsprechend genauso verhalten wie bei C. Dort 
entscheidet er es auf Basis von Objektdateien und nicht von einzelnen 
Funktionen. Wenn du also die Memberfunktionen alle in eigene 
Implementationsfiles steckst, sollte das genauso funktionieren, wie in 
C.
C++ kann da auch sparsamer sein als C:
Eine Klasse, die sich so ähnlich benutzen läßt wie die I/O-Streams aus 
Standard-C++, aber auf das Wesentliche reduziert, kann z.B. kleiner sein 
als printf, weil bei printf immer alle unterstützten Konvertierungen 
gelinkt werden müssen, wogegen beim iostream für jede Konvertierung eine 
eigene Funktion existiert, die nur aufgerufen wird, wenn die 
Konvertierung auch tatsächlich irgendwo verwendet wird. Sehr einfache 
Konvertierungen können auch gleich inline erledigt werden.

von Michael Z. (incunabulum)


Lesenswert?

Rolf Magnus wrote:

>> vorhandenen Problematik, dass immer alle (!) Methoden einer verwendeten
>> Klasse - ob nun genutzt oder nicht - gelinkt werden, zu schweigen.
>
> Sicher? Der Linker hat eigentlich keine Ahnung, ob der Code C oder C++
> ist und sollte sich dementsprechend genauso verhalten wie bei C. Dort
> entscheidet er es auf Basis von Objektdateien und nicht von einzelnen
> Funktionen. Wenn du also die Memberfunktionen alle in eigene
> Implementationsfiles steckst, sollte das genauso funktionieren, wie in
> C.

Also meiner Erfahrung nach schon.... gab auch mal eine schöne Diskussion 
bei der "Konkurenz" (darf ich auf diese Verlinken?)

Zumindest bei Verwendung der Option qc-sections im Linker und 
function-sections im gcc werden Funktionen ohne Klasse nur gelinkt, wenn 
diese verwendet werden. Bei Klassen werden nach meinem Sym-File alle 
Methoden der Klasse gelinkt, unabhängig davon, ob ich diese Verwende 
oder nicht.

Zur Diskussion Klassenframework als HAL:
Also ich hatte mir damals auch so etwas entworfen und zum Teil 
implementiert. Aber wenn insbesondere bei der Hardware alle Methoden 
sowieso Static sein werden, dann hatte ich zumindest in meinem Fall 
keinerlei Vorteile aber einen höheren Speicherverbrauch (vtable im Ram) 
YMMV though :-)

Namespaces, Templates etc. verwende ich aber dennoch gerne. Klassen 
auch, wenn diese Sinn machen. Ringbuffer, Fifo, Stack etc.

@Magnus: Willst du ein Beispiel eines solchen Flash-Smartpointers online 
stellen? Klingt interessant, wobei mir da aber zum eigenständigen 
Umsetzen das Wissen wohl nocht fehlt.

cu, mz

von Andreas K. (a-k)


Lesenswert?

> sowieso Static sein werden, dann hatte ich zumindest in meinem Fall
> keinerlei Vorteile aber einen höheren Speicherverbrauch (vtable im Ram)
> YMMV though :-)

Gibt es ohne virtual member functions überhaupt eine vtable?

> Namespaces, Templates etc. verwende ich aber dennoch gerne. Klassen
> auch, wenn diese Sinn machen. Ringbuffer, Fifo, Stack etc.

Ebenso. Auch critical sections sind in C++ ganz praktisch, mit allem 
Code im constructor/destructor. Kann man nicht versehentlich hängen 
lassen.

Sehr nützlich: buffer template, beispielsweise für Puffer von UARTs und 
anderen Kommunikationsschnittstellen.

von Rolf Magnus (Gast)


Lesenswert?

>> sowieso Static sein werden, dann hatte ich zumindest in meinem Fall
>> keinerlei Vorteile aber einen höheren Speicherverbrauch (vtable im
>> Ram) YMMV though :-)
>
> Gibt es ohne virtual member functions überhaupt eine vtable?

Nein. Eine vtable wird für eine Klasse nur angelegt, wenn sie virtuelle 
Funktionen enthält oder von einer solchen Klasse abgeleitet ist.

> @Magnus:

Das ist mein Nachname.

> Willst du ein Beispiel eines solchen Flash-Smartpointers online
> stellen? Klingt interessant, wobei mir da aber zum eigenständigen
> Umsetzen das Wissen wohl nocht fehlt.

Ich habe so eine Klasse schon vor einer Weile mal geschrieben, und 
dasselbe auch für EEPROM. Leider gibt es ein Problem, das die 
Verwendbarkeit meines Erachtens doch ziemlich einschränkt. Der operator 
-> funtkioniert mit der Klasse nicht, da der sich in C++ nicht so 
überladen läßt, wie ich das bräuchte.

> Ebenso. Auch critical sections sind in C++ ganz praktisch, mit allem
> Code im constructor/destructor.

Stimmt. Ich benutze da gerne eine einfacher interrupt-lock-Klasse, deren 
Destruktor automatisch die Interrupts freigibt.

> Sehr nützlich: buffer template, beispielsweise für Puffer von UARTs und
> anderen Kommunikationsschnittstellen.

Ja.

von Andreas K. (a-k)


Lesenswert?

>> Gibt es ohne virtual member functions überhaupt eine vtable?
>
> Nein. Eine vtable wird für eine Klasse nur angelegt, wenn sie virtuelle
> Funktionen enthält oder von einer solchen Klasse abgeleitet ist.

Eben. Ist also auch zunächst kein Problem.

von yalu (Gast)


Lesenswert?

> Zumindest bei Verwendung der Option qc-sections im Linker und
> function-sections im gcc werden Funktionen ohne Klasse nur gelinkt,
> wenn diese verwendet werden. Bei Klassen werden nach meinem Sym-File
> alle Methoden der Klasse gelinkt, unabhängig davon, ob ich diese
> Verwende oder nicht.

Bei mir (gcc 4.2.1, binutils 2.18) funktioniert das tadellos, sowohl
mit normalen als auch mit Klassenmethoden. Beim Compiler gebe ich
-ffunction-sections, beim Linker --gq-sections an. Die Methoden stehen
alle in der gleichen Quelldatei, werden aber - wie gewünscht - nur bei
Verwendung gelinkt.

Ich programmiere zwar bisher meine AVRs ausschließlich in C, aber
vielleicht stellt sich am Ende dieses Threads heraus, dass C++ doch
die bessere Sprache ist ;-)

Ich bin auf jeden Fall auf weitere Für- und Gegenargumente gespannt.

von Karl H. (kbuchegg)


Lesenswert?

Rolf Magnus wrote:

> Ich habe so eine Klasse schon vor einer Weile mal geschrieben, und
> dasselbe auch für EEPROM. Leider gibt es ein Problem, das die
> Verwendbarkeit meines Erachtens doch ziemlich einschränkt. Der operator
> -> funtkioniert mit der Klasse nicht, da der sich in C++ nicht so
> überladen läßt, wie ich das bräuchte.

Ich nehme an, du sprichst auf den Zugriff innerhalb von struct
an. Das glaub ich dann schon, das das knifflig bis unmöglich
wird (soll ja auch effizient sein)

Für einen einfach Bytepointer sollte aber sowas ausreichen
(nur um Michael mal in die Richtung zu bringen)
Das ganze beruht auf operator overloading

class FlashPtr
{
  public:
    FlashPtr()            :  m_pPtr( 0 )   {}
    FlashPtr( void* Ptr ) :  m_pPtr( Ptr ) {}
    FlashPtr( int Ptr )   :  m_pPtr( (unsigned char*)Ptr )  {}
    FlashPtr( const FlashPtr& arg ) : m_pPtr( arg.m_pPtr ) {}

    unsigned char operator* () const
      { return pgm_read_byte( m_pPtr ); }

  private:
    unsigned char* m_pPtr;
}

int main()
{
  FlashPtr a = 0x123;
  unsigned char b;

  b = *a;
}

Das ganze wird man sinnvollerweise noch in ein Template umwandeln,
wobei man für das Template Spezialisierungen für Byte und Word
macht, da dort ja mit pgm_read_byte, bzw pgm_read_word gearbeitet
werden kann, während im allgmeinen Fall, ja mit Speicherblöcken
gearbeitet werden muss (pgm_read_block, bzw. das Äquivalent mit
einer Schleife und pgm_read_byte).

Besonders interessant wird das Ganze natürlich, so man es sich
leisten kann, wenn man da Klassen für SRAM Pointer, Flash Pointer
und EEPROM Pointer hat, die alle von einer gemeinsamen Basisklasse
abgeleitet sind und virtuelle Operatoren erhalten. Dann kommt man
dem Traum ein Stückchen näher, dass sich eine Funktion die so
einen Pointer erhält, nicht mehr darum kümmern muss, wohin der
Pointer jetzt wirklich zeigt. Das Pointer Objekt weiss schon ganz
von alleine, was es mit der in ihm gespeicherten Adresse anfangen
muss. So gesehen realtiviert sich dann der verbrauchte Speicher
für die vtable wieder, da man keine unterschiedlichen verwendenden
Funktionen für SRAM, Flash bzw. EEPROM mehr braucht. Nur leider
liegt halt die vtable im SRAM und das tut weh.

Disclaimer: Schnell mal so hingeschrieben, da werden also noch
eine Menge Fehler drinnen sein.

von Michael Z. (incunabulum)


Lesenswert?

yalu wrote:
> Bei mir (gcc 4.2.1, binutils 2.18) funktioniert das tadellos, sowohl
> mit normalen als auch mit Klassenmethoden. Beim Compiler gebe ich
> -ffunction-sections, beim Linker --gq-sections an. Die Methoden stehen
> alle in der gleichen Quelldatei, werden aber - wie gewünscht - nur bei
> Verwendung gelinkt.

Sieht so aus, als müsste ich in diesem Falle meine Toolchain updaten 
bzw. genauer suchen, warum dies bei mir nicht klappt. Danke für die 
Info!

Und danke für die Idee hinsichtlich eines Smart-Pointers. Als Fingerzeig 
zum selber denken wirklich das RIchtige! Bei C++ muss ich Python-Mensch 
noch viel lernen :-)

cu, mz

von Rolf Magnus (Gast)


Lesenswert?

> Ich nehme an, du sprichst auf den Zugriff innerhalb von struct

Ja.

> Das glaub ich dann schon, das das knifflig bis unmöglich
> wird (soll ja auch effizient sein)

Der Operator-> müßte halt einen regulären Zeiger auf die Struktur 
zurückgeben und hat dann mit dem eigentlichen Zugriff nichts mehr zu 
tun. Ich weiß nicht mal, ob ein Lese- oder ein Schreibzugriff auf das 
Zielobjekt erfolgen, oder gar eine Memberfunktion davon aufgerufen 
werden soll. Auch gibt es keine Möglichkeit herauszufinden, auf welches 
Element.
Mir ist keine Möglichkeit eingefallen, das Problem zu umgehen. Wenn man 
eine Proxy-Klasse einführt, hat man wieder genau dasselbe Problem.

> Das ganze wird man sinnvollerweise noch in ein Template umwandeln,
> wobei man für das Template Spezialisierungen für Byte und Word
> macht, da dort ja mit pgm_read_byte, bzw pgm_read_word gearbeitet
> werden kann, während im allgmeinen Fall, ja mit Speicherblöcken
> gearbeitet werden muss (pgm_read_block, bzw. das Äquivalent mit
> einer Schleife und pgm_read_byte).

Genau so macht das meine Implementation. Die kann ich heute abend mal 
zusammen mit der fürs EEPROM posten,wenn ich dran denke.

von Simon K. (simon) Benutzerseite


Lesenswert?

Wenn ich mir so die Nützlichkeit einiger Features anhöre, die man in C++ 
hätte, würde ich mir schon wünschen, dass es in ferner Zukunft mal sowas 
wie eine avr-libc++ gibt :-)

Aber, um Gottes Willen, Jörg Wunsch und David und wie sie nicht alle 
heißen: Halst euch nicht noch mehr Arbeit auf.

PS: Der FlashPtr-Klasse könnte man noch den operator++ bzw. operator-- 
hinzufügen ;)

von Rolf Magnus (Gast)


Angehängte Dateien:

Lesenswert?

Im Anhang mal meine bisherige Implementation eines Templates 
pgmspace_ptr mit Doxygen-Doku für deutsch und englisch, mit allen 
Operatoren und mit überladenen Wrappern für gängige 
Standard-C-Funktionen. Dasselbe habe ich auch noch für den EEPROM.
Bisher habe ich es allerdings noch nicht oft eingesetzt.

von Rolf Magnus (Gast)


Lesenswert?

Warum ist es denn auf einmal so still hier? Hat mein Code euch die 
Sprache verschlagen? ;-)

von Simon K. (simon) Benutzerseite


Lesenswert?

Wir warten darauf, dass jemand mit einer kompletten vollständigen 
ausdokumentierten C++ Library vorbeikommt. :-)

*wartet

von Michael Z (Gast)


Lesenswert?

@Rolf,

ich bin noch dabei, deine pgmspace-Classe zu verstehen. Sind auf jeden 
Fall gute Anregungen dabei. Danke dir!

Desweiteren experimentiere ich ein bisschen hinsichtlich der weiteren 
Verwendung von Klassen, also wo sind die Grenzen der (für mich) 
sinnvollen Einsetzbarkeit. Was macht z, B. hinsichtlich Speichergröße, 
Komfort und Flexibilät mehr Sinn: 1) Einer I2C-Funktione jedesmal die 
Adresse übergeben, 2) diese per #define in einem config-File zu 
definieren oder 3) diese beim init() der Klasse zu übergeben und dann 
als private Variable zu speichern.

Warum sollte ich ganz low Level Klassen verwenden? Was kann mir 
Vererbung hier bringen? Meiner Meinung nach wenig.

Fragen, das sich mir hierbei stellen:
1) Kann ich eine Methode einer Klasse aus einer ISR aufrufen, wenn ich 
diese volatile deklariert habe? (noch nicht getestet)

2) Für Ausgabe etc. arbeite ich viel mit Funktoren, d. h. eine 
Handler-Funktion z. B. für writeChar(char c) wird für die Ausgabe zur 
Laufzeit registriert. Über diese werden dann alle Ausgaben 
weitergeleitet.

Wie kann ich über Funktoren Methoden eines Klassenobjektes registrieren? 
Geht bei mir (noch) nicht....


cu, mz

cu, mz (Auch die RAM-Frage, s.o. will noch untersucht werden )

von Daniel W. (danielwidmann)


Lesenswert?

@Rolf,
die Klasse sieht echt interressant aus. Das ist ein gutes Beispeil 
dafür, wie man Klassen sehr komfortabel einsetzen kann, ohne das es viel 
mehr Speicher braucht als das Gleiche in C (Falls es überhaupt mehr 
Speicher benötigt).

Traumhaft wäre wum Beispiel auch eine EEPROM-Zeiger-Klasse, die den 
Zugriff auf einen externen EEPROM-Baustein genau so ermöglich, wie auf 
das interne EEPROM. Als Programmierer wäre man dann deutlich Flexiebler.
Ich denke es gibt auch noch eine ganze Menge von Dingen die Sich 
besonders elagant mit Klassen beschreiben lassen.

Aber zurück auf den Boden der Tatsachen, es gibt leider (noch) keine 
avr-libc++. Aber warum eigentlich? Aus technischer Sicht gibt es 
eigentlich keine größeren Problem. Durch den gcc hat praktisch jeder 
schon einen c++ Compiler installiert. Auch der in C++ geschriebene Code 
benötigt im Vergleich zu C ähnlich viel Speicher (falls sauber 
programmiert wird). Trotzdem fürht c++ bei Mikrocontrollern eher ein 
Nischendasein. Vieleicht, weil es keine KLassenbibiothek giebt (--> ein 
Teufelskreis g)

Da sich ein Klassenbibiothek nicht einfach aus dem Ärmel schütteln 
lässt, wäre es zumindest ein Anfang, wenn man die Klassen von 
verschiedenen Leuten sammelt. Vieleicht gibt es noch mehr Leute wie 
Rolf, die schon das ein oder andere Programmiert haben.

Auch wäre es sicher hilfreich, wenn man ein paar Relgen hätte, was man 
auf Mikrocontrollern machten sollte und was besser nicht. Denn das 
Meiste, was man zu C++ findet, bezieht sich auf PCs.


Gruss Daniel

von Michael Z. (incunabulum)


Lesenswert?

Daniel Widmann wrote:

> Vieleicht gibt es noch mehr Leute wie
> Rolf, die schon das ein oder andere Programmiert haben.

Mal 2 kleine template basierte Buffer-Klassen:

Ringbuffer: http://mz.incunabulum.de/avr/RBuffer.h
FiFo: http://mz.incunabulum.de/avr/Fifo.h

Erstere stammt aus einem Forum und wurde leicht modifiziert, letztere 
dann durch mich daraus abgeleitet.

cu, mz

von Jorge (Gast)


Lesenswert?

Ich bin eigentlich C++-Fan. Argumente dagegen:

- es fragt sich jetzt warum das meiste an systemnahen Programmen unter 
Unix in "C" geschrieben ist

- auf eine fremdhergestellte C++-Klasse kann man sich nicht 100%ig 
verlassen ausser vielleicht wenn man sie selbst hergestellt hat und auch 
dann nicht

- objektorientiert konnte man in "C" und Assembler schon immer machen 
nur C++ hat den einen oder anderen erst dazu gebracht.

- man kann via C++ nicht über seinen Schatten springen muss also 
trotzdem Probleme systematisch angehen

- vmt im RAM geht halt nicht anders wegen der Architektur (oder doch?). 
Das heisst von 1kByte RAM bleiben 25 Bytes für Variablen, dann noch die 
32 Allzweckregister

- alles in C zu können ist die grössere Kunst

von Rolf Magnus (Gast)


Lesenswert?

> - es fragt sich jetzt warum das meiste an systemnahen Programmen unter
> Unix in "C" geschrieben ist

Weil es bisher noch keine brauchbaren Libs gibt und weil viele die 
Vorteile nicht kennen oder weil sie glauben, C++ bedeute einen riesigen 
Overhead.

> - auf eine fremdhergestellte C++-Klasse kann man sich nicht 100%ig
> verlassen ausser vielleicht wenn man sie selbst hergestellt hat und
> auch dann nicht

Warum spricht das gegen C++? Das ist doch bei C genauso.

> - objektorientiert konnte man in "C" und Assembler schon immer machen
> nur C++ hat den einen oder anderen erst dazu gebracht.

Vor allem ist es in C++ schon eingebaut, wodurch es sich viel eleganter 
formulieren läßt. Hast du schon mal versucht, in C wirklich 
objektorientiert zu programmieren? Das wird schnell ziemlich häßlich.

> - man kann via C++ nicht über seinen Schatten springen muss also
> trotzdem Probleme systematisch angehen

Auch hier sehe ich nicht, warum das gegen C++ sprechen sollte. Klar löst 
C++ meine Probleme nicht für mich, aber C tut das auch nicht.

> - vmt im RAM geht halt nicht anders wegen der Architektur (oder doch?).

Sicher ginge das. Nicht die Architektur, sondern der Compiler ist hier 
das Problem. gcc ist voll auf von-Neumann-Architekturen ausgerichtet. Er 
weiß nichts von verschiedenen Speichertypen. Deshalb gibt es ja den 
ganzen Umstand mit pgm_read_*. Die vtables werden intern einfach als 
Variablen angelegt. Wenn man direkt auf eine Variable zugreift, muß die 
aber zwingend im RAM stehen, und irgendwo mitten in C++-Compiler kann 
man eben nicht einfach so ein pgm_read_word einpflanzen.

> Das heisst von 1kByte RAM bleiben 25 Bytes für Variablen, dann noch die
> 32 Allzweckregister

Hm? Die vtable braucht pro virtueller Funktion und Klasse einen Zeiger.

> - alles in C zu können ist die grössere Kunst

Du denkst also, daß es in C schwieriger ist, spricht gegen C++?

von Joachim (Gast)


Lesenswert?

Hallo,

wäre schön, wenn das hier nicht in eine Diskussion darüber ausartet,
ob C++ nun gut oder schlecht oder besser als C ist.
Es gibt wie so oft auf beiden Seiten Vor- und Nachteile und C++
ist sicher nicht kompromisslos auf Mikrocontrollern einzusetzen.
Manchmal nimmt man aber ja vielleicht auch die Nachteile einer
Seite in Kauf da man sich dadurch auch anderswo Vorteile schafft.

Darum fände ich es schön, wenn hier Code oder Beiträge erscheinen,
die C++ auf Mikrocontrollern in einem sinnvollen Rahmen erlauben
oder einem wirklich auf Grund der Objektorientierung "das Leben
leichter machen". Das Ganze hat natürlich auch "Gummibandgrenzen" :-)
Ich lerne nämlich gerne dazu :-)

@Rolf:
Den Beitrag von Jorge hatte ich nicht gegen C+++ verstanden, sondern
ich verstand es als "Bremse" gegen den doch sehr verbreiteten Hype
um C++ (die Lösung und alle ist toll und rosa).  gähn
Deine Argumente stimmen schon zu großen Teil, aber es ist nichts
wirkliches dafür oder dagegen, eher philosophisch.

Habt ein schönes Wochenende.
Joachim

von sous (Gast)


Lesenswert?

> - alles in C zu können ist die grössere Kunst

Ja eben: Kunst.
Besser als Kunst wäre jedoch Handwerk!

von Michael Z. (incunabulum)


Lesenswert?

Gerade durch Zufall per RSS gefunden:

http://avr-cpp-lib.sourceforge.net/

Eine C++ Bibliothek für einige AVRs mit rudimentärem (?) New/Delete 
Support etc. Allerdings muss ich zugeben, dass ich die Details noch 
nicht so richtig begriffen habe...

cu, mz

von Andreas K. (a-k)


Lesenswert?

> Weil es bisher noch keine brauchbaren Libs gibt und weil viele die
> Vorteile nicht kennen oder weil sie glauben, C++ bedeute einen riesigen
> Overhead.

Und weil die real existenten C++ Libs eine nicht unerhebliche Chance 
beinhalten, zuerst einmal diese Libs debuggen und fehlende oder falsche 
Dokumentation durch eingehendes Studium unlesbaren Quellcodes ersetzen 
zu müssen.

> Warum spricht das gegen C++? Das ist doch bei C genauso.

Nicht ganz. Die klassischen Systeminterfaces sind meist recht alt, 
relativ sauber definiert und stabil. Bei C++ Libs wird alle paar Jahre 
eine neue Sau durch's Dorf getrieben und du darfst von vorne anfangen.

von Rolf Magnus (Gast)


Lesenswert?

> Eine C++ Bibliothek für einige AVRs mit rudimentärem (?) New/Delete
> Support etc.

new und delete sind auch nicht weiter schwierig.

> Allerdings muss ich zugeben, dass ich die Details noch nicht so richtig
> begriffen habe...

Ist auch etwas schwierig, beim "User Guide in Estonian" ;-)
Im Ernst: Der Code sieht aus, als sei er von einem Java-Programmierer 
geschrieben, der mit C++ gerade erst angefangen hat. Er macht viele 
Dinge so, wie sie in Java Konvention oder gar vorgeschrieben sind, die 
aber überhaupt nicht denen der C++-Standardlib entsprechen und teilweise 
in C++ auch komplett falsch sind. Beispiel:
1
StaticArray()
2
{
3
    BaseArray<DataType, SizeType, DataType[array_capacity]>();
4
}

Hier wird im Konstruktor von StaticArray ein lokales BaseArray der 
gleichen Kapazität angelegt und gleich wieder zerstört. Wohl eher nicht 
das, was der Autor im Sinne hatte.

Und dann so seltsame Dinge wie ein operator() für std::string, der dann 
einen C-String zurückliefert. Dafür fehlt beim Array der eigentlich 
obligatorische operator[] ganz.

>> Warum spricht das gegen C++? Das ist doch bei C genauso.
>
> Nicht ganz. Die klassischen Systeminterfaces sind meist recht alt,
> relativ sauber definiert und stabil. Bei C++ Libs wird alle paar Jahre
> eine neue Sau durch's Dorf getrieben und du darfst von vorne anfangen.

Der Thread hier bezieht sich speziell auf AVR und darauf, eine eigene 
C++-Lib zu schreiben. Da gibt's keine alten "klassischen 
Systeminterfaces", und ob sich die C++-Libs ändern, hätte man dann 
selbst in der Hand.

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?

So wie ich das als C++-Laie* sehe hat C++ das Problem dass es zu viele 
Möglichkeiten und zu wenig allgemein beachtete Konventionen gibt. Sicher 
kann man mit C++ schön sauberen Code schreiben, dummerweise hat jeder 
eine andere Vorstellung davon WIE sauberer C++-Code auszusehen hat, und 
durch die Flexibilität von C++ führt das dazu dass fast jedes Projekt 
völlig anders aussieht. Das fängt schon bei so elementaren Dingen wie 
Strings an: der eine verwendet MFC-Strings, der andere STL-Strings, der 
nächste QT-Strings, wieder ein anderer die klassischen C-Strings, und 
manch einem ist das nicht gut genug und er schreibt sich seine eigene 
String-Klasse. Ich will nicht in der Haut dessen stecken der diese 
Projekte kombinieren muss.

* kann C++ halbwegs lesen, hab aber nie Bedarf gesehen es anzuwenden

von asdf (Gast)


Lesenswert?

@Andreas:

100% ACK!

von Achim (Gast)


Lesenswert?

da der letzte Beitrag schon über 10 Jahre her ist.. gibt es hier was 
neues? Haben sich mittlerweile C++ Bibliotheken im Programmieren von 
Mikrocontrollern etabliert?

von Wilhelm M. (wimalopaan)


Lesenswert?

Wir haben C++20 (fast)!
Seit C++14/17 ist C++ DIE Sprache für kleine µC.

von MitLeserin (Gast)


Lesenswert?

@Achim

Etabliert? wenn ich hier im Forum schaue: nicht wirklich. Unendliche 
Diskussionen über "für" und "wider", .. geschätzt 4..5 Foristen wissen 
was Sache ist ..

Vorhanden? ja, ich kenne zwei, beide brauchbar, beide im wesentlichen 
undokumentiert, einmal -std=c++03, einmal -std=c++2a -fconcepts,
beide muss man verstehen um sie zu nutzen.

Sinnvoll? In meinen Augen sicher. Software sollte modular sein und mit 
<template>c++ ist das für uController realisierbar.

von Wilhelm M. (wimalopaan)


Lesenswert?

MitLeserin schrieb:
> @Achim
>
> Etabliert? wenn ich hier im Forum schaue: nicht wirklich. Unendliche
> Diskussionen über "für" und "wider", .. geschätzt 4..5 Foristen wissen
> was Sache ist ..

Und (N -5)-Foristen wissen gar nicht, was Sache ist. Sie meinen aber,
alles was mit C++ zu tun rundweg ablehnen zu müssen.

von Oliver S. (oliverso)


Lesenswert?

MitLeserin schrieb:
> Vorhanden? ja, ich kenne zwei, beide brauchbar, beide im wesentlichen
> undokumentiert, einmal -std=c++03, einmal -std=c++2a -fconcepts,
> beide muss man verstehen um sie zu nutzen.

Links ?

Oliver

von Markus F. (mfro)


Lesenswert?

MitLeserin schrieb:
> Etabliert? wenn ich hier im Forum schaue: nicht wirklich. Unendliche
> Diskussionen über "für" und "wider", .. geschätzt 4..5 Foristen wissen
> was Sache ist ..

Geschätzte 4 von 5 Foristen schreiben mehr Unsinn im Forum als Code in 
ihrer IDE...

von Anton M. (antonm)


Lesenswert?

MitLeserin schrieb:
> Software sollte modular sein und mit
> <template>c++ ist das für uController realisierbar.

Modularität lässt sich mit nahezu jeder Programmiersprache realisieren.
Wenn man C++ wirklich beherrscht mag das eine tolle Sache sein. Bis 
dahin ist es aber ein steiniger Weg. Kein Wunder, dass die meisten bei C 
oder gar Asm hängenbleiben (und so ihre Projekte genauso auf die Bühne 
bringen).
Eine C++ Klassenbibliothek für AVR klingt gut, allein, es scheitert an 
der Vielzahl der AVR Typen.

von MitLeserin (Gast)


Angehängte Dateien:

Lesenswert?

Anton M. schrieb:
> Eine C++ Klassenbibliothek für AVR klingt gut, allein, es scheitert an
> der Vielzahl der AVR Typen.

Das sehe ich anders. Lässt sich prima und mit System kapseln. Angefügtes 
Beispiel für Timer von ATtiny861. Ich brauche für mich ja nur die Typen 
und Funktionen die ich verwende.

Links: Mcucpp
Beitrag "Re: C++ Arduino Grundlagen"

von S. R. (svenska)


Lesenswert?

MitLeserin schrieb:
> Ich brauche für mich ja nur die Typen
> und Funktionen die ich verwende.

Was genau das Problem mit "einer Klassenbibliothek für AVR" ist.

von MitLeserin (Gast)


Lesenswert?

Es ist schon alles da was man braucht und wenn ein Typ und/oder eine 
Funktion fehlt, so lässt sich das ohne Probleme ergänzen. ATtiny861 zum 
Beispiel.

Wer keine Klassenbibliothek für AVR kennt, der kann auch nicht 
behaupten, dass das nicht und niemals funktioniert ...
<EOF>

von S. R. (svenska)


Lesenswert?

MitLeserin schrieb:
> Es ist schon alles da was man braucht und wenn ein Typ und/oder eine
> Funktion fehlt, so lässt sich das ohne Probleme ergänzen.

Was vollkommen dem Prinzip widerspricht, eine allgemeine und 
vollständige Bibliothek zu haben. Die avr-libc versucht das garnicht 
erst.

Ich hätte das "einer" fett schreiben sollen...

MitLeserin schrieb:
> Wer keine Klassenbibliothek für AVR kennt, der kann auch nicht
> behaupten, dass das nicht und niemals funktioniert ...

Hab ich das? Nein.

Ich habe nur gesagt, dass "ich brauche nur das, was ich nutze" ein 
Problem ist. Weil 90% der Nutzer von Word nur 10% der Funktionen 
brauchen, aber eben nicht die gleichen 10% - und das macht ein "one size 
fits all" doof.

Und deswegen gibt es mehrere Bibliotheken.
In unterschiedlicher Qualität, Funktionalität und Lebendigkeit.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

wenn ich den Thread so lese, dann fällt mir dazu nur eines ein. In den 
12 Jahren hat sich Arduino entwickelt. Da sind Klassen drin ohne Ende. 
Soweit Hardware unabhängig wie nur möglich. Dem einen ist das zu viel, 
dem anderen noch zu wenig. Aber ich denke das ist genau das was der TO 
vor 12 Jahren gesucht hat und damals nicht bekommen konnte.  :-)

von c-hater (Gast)


Lesenswert?

Veit D. schrieb:

> wenn ich den Thread so lese, dann fällt mir dazu nur eines ein. In den
> 12 Jahren hat sich Arduino entwickelt. Da sind Klassen drin ohne Ende.
> Soweit Hardware unabhängig wie nur möglich.

Und es zeigt natürlich alle Vorteile von C++ voll auf: Das primitive 
Wackeln eines Pins dauert statt 2 (wie in Asm oder sogar noch in pure C) 
nunmehr ca. 100 Takte...

Mehr braucht es eigentlich nicht, um den ganzen Wahnsinn sinnlos 
ausufernderer Abstraktionen ganz gnadenlos aufzuzeigen...

Beitrag #5719708 wurde vom Autor gelöscht.
von Veit D. (devil-elec)


Lesenswert?

Hallo,

das liegt laut meiner Meinung nicht an C++. Das liegt daran, soweit ich 
das einschätzen kann, dass es zu Anfangszeiten von Arduino vielleicht 
kein constexpr zur Verfügung stand. Mit heutigen Stand der C++ 
Entwicklung kann man durchaus ein Pin toggle mit 8MHz erreichen bei 
16MHz Haupttakt. Wobei C++11 ausreicht. Habe das selbst schon probieren 
dürfen. Anzumerken ist das der Code dazu nicht von mir stammt. 
Wohlgemerkt mit Arduino IDE setup und loop. Das bedeutet irgendwelche 
Abstraktionen müssen keine Bremswirkung haben.

von 900ss (900ss)


Lesenswert?

c-hater schrieb:
> Und es zeigt natürlich alle Vorteile von C++ voll auf: Das primitive
> Wackeln eines Pins dauert statt 2 (wie in Asm oder sogar noch in pure C)
> nunmehr ca. 100 Takte...

Wenn man es in C++ dumm anställt, dann ist das sicher so.
Wenn man es gut macht, dann ist der C++ Code genauso effektiv.
Es gibt Situationen, wo er sogar besser ist. Das haben schon ein paar 
Leute bewiesen. Ist also wie immer, es kommt auch auf den Teil vor dem 
Bildschirm an und C++ ist deshalb nicht per se weniger performant.

Wo ich dir Recht gebe, wenn die Abstraktion übertrieben wird, dann wird 
C++ Code völlig unübersichtlich. Der Entwickler brüstet sich aber, wie 
toll er C++ beherrscht :)

: Bearbeitet durch User
von Christoph M. (mchris)


Lesenswert?

>Wenn man es in C++ dumm anställt, dann ist das sicher so.
>Wenn man es gut macht, dann ist der C++ Code genauso effektiv.
>Es gibt Situationen, wo er sogar besser ist.

So weit ich das sehen kann, war das ohnehin nur Polemik.
Mittlerweile sehe ich aber, dass zumindest Assembler schneller als C 
ist.

Falls jemand Lust hat, das Gegenteil zu zeigen, kann er es hier beim 
Vergleich von Assembler zu C unter Beweis stellen:
Beitrag "Re: GIGATRON Emulator im STM32"

Beitrag #5720367 wurde von einem Moderator gelöscht.
von Veit D. (devil-elec)


Lesenswert?

Hallo

Ich habe nichts gegen Assembler und nichts gegen irgendeine andere 
Programmiersprache. Nutze selbst C++. Ich kann jedoch der ewigen 
Diskussion Assembler vs. C/C++ nichts abgewinnen. Alles hat seine 
Berechtigung. Im Fall vom schnellen Pin schalten weiß ich jedoch das es 
mit C++ keine Geschwindigkeitseinbußen geben muss. Der Vergleich hinkt 
allgemein sowieso. Denn unter Assembler ist Abstraktion so nicht 
möglich. Hier muss man alles zu Fuss machen. Deswegen ist der Vergleich 
nicht Zielführend. In diesem Thread gehts um C++. Und wäre Arduino heute 
entstanden, bin ich mir sicher das "digitalWrite" anders programmiert 
wurden wäre. Zudem das die Einzigste "Schwachstelle" ist - 
Geschwindigkeit betrachtet. Auf absoluten Speed kommt es meistens auch 
gar nicht an. Es kommt nur darauf an das das Programm für die Aufgabe 
schnell genug ist. Ob sich der µC dabei mehr oder weniger langweilt ist 
zweitrangig. Die eigentliche Aufgabe muss erfüllt sein.

von MitLeserin (Gast)


Angehängte Dateien:

Lesenswert?

Ein Minimal-Beispiel:
********************
toggle auf Pin1 von Portb

von Carl D. (jcw2)


Lesenswert?

Veit D. schrieb:
> Hallo
>
> Ich habe nichts gegen Assembler und nichts gegen irgendeine andere
> Programmiersprache. Nutze selbst C++. Ich kann jedoch der ewigen
> Diskussion Assembler vs. C/C++ nichts abgewinnen. Alles hat seine
> Berechtigung. Im Fall vom schnellen Pin schalten weiß ich jedoch das es
> mit C++ keine Geschwindigkeitseinbußen geben muss. Der Vergleich hinkt
> allgemein sowieso. Denn unter Assembler ist Abstraktion so nicht
> möglich. Hier muss man alles zu Fuss machen. Deswegen ist der Vergleich
> nicht Zielführend. In diesem Thread gehts um C++. Und wäre Arduino heute
> entstanden, bin ich mir sicher das "digitalWrite" anders programmiert
> wurden wäre. Zudem das die Einzigste "Schwachstelle" ist -
> Geschwindigkeit betrachtet. Auf absoluten Speed kommt es meistens auch
> gar nicht an. Es kommt nur darauf an das das Programm für die Aufgabe
> schnell genug ist. Ob sich der µC dabei mehr oder weniger langweilt ist
> zweitrangig. Die eigentliche Aufgabe muss erfüllt sein.

Vermutlich kann man das "digitalWrite"-Problem durch LTO lösen (werde 
ich irgendwann probieren), da eigentlich (über alles betrachtet) zur 
Compile-Zeit bekannt sein, welcher Pin verwendet wird und deshalb nicht 
jedesmal untersucht werden muß, ob man noch PWM ausschalten muß. Da dies 
aber keine "Header-only"-Lib ist, kann der Compiler da nicht weit genug 
optimieren.

Überhaupt, wenn man PWM benutzt, dann ist der Pin eben belegt und kann 
nicht noch eine zweite Funktion haben. Ein Teil des Arduino-Erfolgs ist 
sicher der Skrupellosigkeit der Macher zu verdanken, auch Halbgares auf 
den Markt zu bringen.

Und zu der unsäglichen Diskussion:
Es soll viele geben, die Assembler nicht beherrschen. Da ist doch der 
hinreichende Beleg, das das nichts taugt, oder. Zumindest nach aktueller 
Hass-Lehre/Leere.

: Bearbeitet durch User
Beitrag #5720841 wurde von einem Moderator gelöscht.
von 900ss (900ss)


Lesenswert?

Anton M. schrieb im Beitrag #5720841:
> Minimal

Weshalb kapiert das niemand? Es geht hier nicht um Assembler.

von Anton M. (antonm)


Lesenswert?

Veit D. schrieb:
> Denn unter Assembler ist Abstraktion so nicht möglich.

Dafür ist Asm auch nicht entworfen.
Abstraktion macht Sinn bei komplexen Funktionalitäten und 
Datenstrukturen.

> Hier muss man alles zu Fuss machen.

Dennoch gilt wie überall: Auf bereits vorhandenem Code kann man 
aufbauen!


> Ob sich der µC dabei mehr oder weniger langweilt ist
> zweitrangig. Die eigentliche Aufgabe muss erfüllt sein.

Stimmt. Die "eigentliche Aufgabe" steht in solchen Diskussionen viel zu 
selten im Mittelpunkt.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

>> Ob sich der µC dabei mehr oder weniger langweilt ist
>> zweitrangig. Die eigentliche Aufgabe muss erfüllt sein.
>
> Stimmt. Die "eigentliche Aufgabe" steht in solchen Diskussionen viel zu
> selten im Mittelpunkt.

Sehr schön. Es geht darum dem Anwender eine Klasse und dessen Methoden 
in die Hand zugeben die für ihn immer gleich bleiben. Der 
Klassenentwickler ergänzt für neue µC nur noch seine Pindefs und fertig 
ist die Laube. Das schnelle schalten wurde/wird übrigens mit intensiven 
Einsatz von constexpr und inline Methoden gemacht. Sodass alles zur 
Compilerzeit erledigt werden kann. Grundgerüst sind Register Arrays für 
die Ports. Die Reihenfolge ist dann die gewünschte Pindurchnummerierung. 
Wie gesagt, die Idee ist nicht von mir. Da hat sich ein anderer einen 
richtigen Kopf gemacht.

von Yalu X. (yalu) (Moderator)


Lesenswert?

MitLeserin schrieb:
> Ein Minimal-Beispiel:
> ********************
> toggle auf Pin1 von Portb

Der von dir verwendete ATmega644[P][A] unterstützt Pin-Toggling per
Schreibzugriff auf die PIN-Register. Wenn du dir schon die Mühe machst,
eine Toggle-Funktion zu schreiben, könntest du dies berücksichtigen und
damit den Code in der Schleife von

1
  in  r25, 0x3f
2
  cli
3
  in  r24, 0x05
4
  eor  r24, r18
5
  out  0x05, r24
6
  out  0x3f, r25

auf

1
  out  0x03, r24

bzw.

1
  sbi  0x03, 1

reduzieren.

von Carl D. (jcw2)


Lesenswert?

Yalu X. schrieb:
> MitLeserin schrieb:
>> Ein Minimal-Beispiel:
>> ********************
>> toggle auf Pin1 von Portb
>
> Der von dir verwendete ATmega644[P][A] unterstützt Pin-Toggling per
> Schreibzugriff auf die PIN-Register. Wenn du dir schon die Mühe machst,
> eine Toggle-Funktion zu schreiben, könntest du dies berücksichtigen und
> damit den Code in der Schleife von ...

Das war nicht selbstgeschrieben, sondern aus MCUCPP. Das ist aber aus 
der Zeit vor C++11 und nicht trivial anpassbar.

von Yalu X. (yalu) (Moderator)


Lesenswert?

c-hater schrieb:
> Veit D. schrieb:
>
>> wenn ich den Thread so lese, dann fällt mir dazu nur eines ein. In den
>> 12 Jahren hat sich Arduino entwickelt. Da sind Klassen drin ohne Ende.
>> Soweit Hardware unabhängig wie nur möglich.
>
> Und es zeigt natürlich alle Vorteile von C++ voll auf: Das primitive
> Wackeln eines Pins dauert statt 2 (wie in Asm oder sogar noch in pure C)
> nunmehr ca. 100 Takte...

Veit D. schrieb:
> das liegt laut meiner Meinung nicht an C++. Das liegt daran, soweit ich
> das einschätzen kann, dass es zu Anfangszeiten von Arduino vielleicht
> kein constexpr zur Verfügung stand.

Das ist auch nicht unbedingt erforderlich. Da Arduino ohnehin an einen
bestimmten Compiler, nämlich den GCC, gebunden ist, hätte man dessen
Optimierungsfähigkeiten (die auch vor 12 Jahren schon überragend waren)
gezielt für solche Zero-Cost-Abstraktionen nutzen können. Dazu hätte es
nicht einmal C++ bedurft, gewöhnliches C hätte (speziell dafür) auch
schon gereicht.

> Mit heutigen Stand der C++ Entwicklung kann man durchaus ein Pin
> toggle mit 8MHz erreichen bei 16MHz Haupttakt. Wobei C++11 ausreicht.

Dann wäre es spätestens jetzt an der Zeit, diese Digital-I/O-Funktionen
der Arduino-Bibliothek entsprechend zu überarbeiten. Natürlich muss sich
dazu jemand finden, der zum einen dafür genug Ahnung hat, der aber zum
anderen darin auch genügend persönlichen Nutzen sieht (oder wenigstens
Genugtuung empfindet), um die dafür benötigte Zeit zu investieren.


Carl D. schrieb:
> Das war nicht selbstgeschrieben, sondern aus MCUCPP. Das ist aber aus
> der Zeit vor C++11 und nicht trivial anpassbar.

Ah, danke, das hatte ich übersehen.

von Christoph M. (mchris)


Lesenswert?

Yalu schrieb:
> Da Arduino ohnehin an einen
>bestimmten Compiler, nämlich den GCC, gebunden ist, hätte man dessen
>Optimierungsfähigkeiten (die auch vor 12 Jahren schon überragend waren)
>gezielt für solche Zero-Cost-Abstraktionen nutzen können. Dazu hätte es
>nicht einmal C++ bedurft, gewöhnliches C hätte (speziell dafür) auch
>schon gereicht.

Ich gehe mal davon aus, dass Du nur an Projekten beteiligt warst, die 
nie als Provisorium lange überlebt haben und schon von Anfang an perfekt 
waren, oder?

von Veit D. (devil-elec)


Lesenswert?

Hallo,

muss mich korrigieren. Sind 4MHz - keine 8MHz. Ich denke das kann man 
vernachlässigen wenn man dafür den Vorteil der Klasse/Abstraktion 
bekommt. Man lässt sicherlich nicht einen Pin ohne Pause in der 
Hauptschleife takten. Sondern man möchte nur die Ausführungszeit des 
Schaltvorgangs beschleunigen an dem Punkt im Programm.

Die Änderung in der Arduino Klasse wird einen sehr langen Rattenschwanz 
nach sich ziehen. Wer soll das alles testen? Für die ATmegas mag das 
noch einfach änderbar sein. Beim Zero mit seinem SAM µC sieht das schon 
anders aus. Wenn ich der Entwickler wäre würde ich mir wohl kaum alle 
Arduinoboards kaufen. Eine nachträgliche Änderung in dem Umfang ist 
immer sehr schwierig.

Gibt es constexpr in C? Kenne ich nur für C++. Ohne dem gehts laut 
meines Wissen nicht.

Beitrag #5722150 wurde von einem Moderator gelöscht.
von Veit D. (devil-elec)


Lesenswert?

Hallo,

stimmt so nicht. Der Rattenschwanz bezog sich viel mehr auf das testen 
mit allen Boards, wenn es in den Hauptcode von Arduino einziehen soll. 
Wenn die Klasse einmal steht, dann ist es leicht für andere µC 
Ergänzungen vorzunehmen. Dann spielt die Abstraktion ihre Vorteile aus.
Du vergleichst momentan eine alte Klasse mit einer neuen Klasse. 
Natürlich muss man hier erstmal schauen und kann nicht blind Code 
ändern.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

ich habe das Grundgerüst der Register-Arrays "rausgezogen" und nach 
Vorbild der Klasse einen Ersatz für digitalWrite hinzugefügt. 
digitalSwitch genannt um erstmal Kollisionen zuvermeiden.

Der Erfinder der kompletten Klasse ist übrigens Arduino Fanboy. Er hat 
eine Klasse erschaffen mit allen Features inkl. kompletter 
Datenkapselung. Dabei steht alles zur Laufzeit fest.

Meine Abwandlung ist natürlich keine Klasse in dem Sinne. Das ist mir 
bewusst. Ich wollte nur probieren ob damit ein schnellerer Ersatz für 
digitalWrite möglich ist.

PortBitList.h
1
#pragma once
2
3
4
using Register = volatile uint8_t *;
5
6
namespace
7
{
8
  /* noch im Test
9
  constexpr uint8_t LOW  = 0;
10
  constexpr uint8_t HIGH = 1;
11
  
12
  constexpr uint8_t INPUT  = 0;
13
  constexpr uint8_t OUTPUT = 1;
14
  constexpr uint8_t INPUT_PULLUP = 2;
15
  */  
16
  
17
  // Die Arrays bitte nicht händisch ändern
18
  // Der Index ist jeweils die Arduino Pinnummer
19
    
20
  // UNO, Nano, Pro Mini usw.
21
  #if defined(__AVR_ATmega328P__) | defined(__AVR_ATmega328__) | defined(__AVR_ATmega168P__) | defined(__AVR_ATmega168__)  
22
   constexpr uint8_t portBit[]   = {0,1,2,3,4,5,6,7,0,1,2,3,4,5,0,1,2,3,4,5};
23
   constexpr uint8_t pinMaske[]  = {0b1,0b10,0b100,0b1000,0b10000,0b100000,0b1000000,0b10000000,0b1,0b10,0b100,0b1000,0b10000,0b100000,0b1,0b10,0b100,0b1000,0b10000,0b100000};
24
   constexpr Register portList[] = {&PORTD,&PORTD,&PORTD,&PORTD,&PORTD,&PORTD,&PORTD,&PORTD,&PORTB,&PORTB,&PORTB,&PORTB,&PORTB,&PORTB,&PORTC,&PORTC,&PORTC,&PORTC,&PORTC,&PORTC};
25
   constexpr Register ddrList[]  = {&DDRD,&DDRD,&DDRD,&DDRD,&DDRD,&DDRD,&DDRD,&DDRD,&DDRB,&DDRB,&DDRB,&DDRB,&DDRB,&DDRB,&DDRC,&DDRC,&DDRC,&DDRC,&DDRC,&DDRC};
26
   constexpr Register pinList[]  = {&PIND,&PIND,&PIND,&PIND,&PIND,&PIND,&PIND,&PIND,&PINB,&PINB,&PINB,&PINB,&PINB,&PINB,&PINC,&PINC,&PINC,&PINC,&PINC,&PINC};
27
  // #endif 
28
29
  // Leonardo, Micro, usw.
30
  #elif defined(__AVR_ATmega32U4__)
31
   constexpr uint8_t portBit[]   = {2,3,1,0,4,6,7,6,4,5,6,7,6,7,3,1,2,0,7,6,5,4,1,0};          
32
   constexpr uint8_t pinMaske[]  = {0b100,0b1000,0b10,0b1,0b10000,0b1000000,0b10000000,0b1000000,0b10000,0b100000,0b1000000,0b10000000,0b1000000,0b10000000,0b1000,0b10,0b100,0b1,0b10000000,0b1000000,0b100000,0b10000,0b10,0b1};
33
   constexpr Register portList[] = {&PORTD,&PORTD,&PORTD,&PORTD,&PORTD,&PORTC,&PORTD,&PORTE,&PORTB,&PORTB,&PORTB,&PORTB,&PORTD,&PORTC,&PORTB,&PORTB,&PORTB,&PORTB,&PORTF,&PORTF,&PORTF,&PORTF,&PORTF,&PORTF};
34
   constexpr Register ddrList[]  = {&DDRD,&DDRD,&DDRD,&DDRD,&DDRD,&DDRC,&DDRD,&DDRE,&DDRB,&DDRB,&DDRB,&DDRB,&DDRD,&DDRC,&DDRB,&DDRB,&DDRB,&DDRB,&DDRF,&DDRF,&DDRF,&DDRF,&DDRF,&DDRF};
35
   constexpr Register pinList[]  = {&PIND,&PIND,&PIND,&PIND,&PIND,&PINC,&PIND,&PINE,&PINB,&PINB,&PINB,&PINB,&PIND,&PINC,&PINB,&PINB,&PINB,&PINB,&PINF,&PINF,&PINF,&PINF,&PINF,&PINF};
36
  // #endif   
37
38
  // Mega
39
  #elif defined(__AVR_ATmega2560__) | defined(__AVR_ATmega1280__)
40
   constexpr uint8_t portBit[]   = {0,1,4,5,5,3,3,4,5,6,4,5,6,7,1,0,1,0,3,2,1,0,0,1,2,3,4,5,6,7,7,6,5,4,3,2,1,0,7,2,1,0,7,6,5,4,3,2,1,0,3,2,1,0,0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7};
41
   constexpr uint8_t pinMaske[]  = {0b1,0b10,0b10000,0b100000,0b100000,0b1000,0b1000,0b10000,0b100000,0b1000000,0b10000,0b100000,0b1000000,0b10000000,0b10,0b1,0b10,0b1,0b1000,0b100,0b10,0b1,0b1,0b10,0b100,0b1000,0b10000,0b100000,0b1000000,0b10000000,0b10000000,0b1000000,0b100000,0b10000,0b1000,0b100,0b10,0b1,0b10000000,0b100,0b10,0b1,0b10000000,0b1000000,0b100000,0b10000,0b1000,0b100,0b10,0b1,0b1000,0b100,0b10,0b1,0b1,0b10,0b100,0b1000,0b10000,0b100000,0b1000000,0b10000000,0b1,0b10,0b100,0b1000,0b10000,0b100000,0b1000000,0b10000000};
42
   constexpr Register portList[] = {&PORTE,&PORTE,&PORTE,&PORTE,&PORTG,&PORTE,&PORTH,&PORTH,&PORTH,&PORTH,&PORTB,&PORTB,&PORTB,&PORTB,&PORTJ,&PORTJ,&PORTH,&PORTH,&PORTD,&PORTD,&PORTD,&PORTD,&PORTA,&PORTA,&PORTA,&PORTA,&PORTA,&PORTA,&PORTA,&PORTA,&PORTC,&PORTC,&PORTC,&PORTC,&PORTC,&PORTC,&PORTC,&PORTC,&PORTD,&PORTG,&PORTG,&PORTG,&PORTL,&PORTL,&PORTL,&PORTL,&PORTL,&PORTL,&PORTL,&PORTL,&PORTB,&PORTB,&PORTB,&PORTB,&PORTF,&PORTF,&PORTF,&PORTF,&PORTF,&PORTF,&PORTF,&PORTF,&PORTK,&PORTK,&PORTK,&PORTK,&PORTK,&PORTK,&PORTK,&PORTK};
43
   constexpr Register ddrList[]  = {&DDRE,&DDRE,&DDRE,&DDRE,&DDRG,&DDRE,&DDRH,&DDRH,&DDRH,&DDRH,&DDRB,&DDRB,&DDRB,&DDRB,&DDRJ,&DDRJ,&DDRH,&DDRH,&DDRD,&DDRD,&DDRD,&DDRD,&DDRA,&DDRA,&DDRA,&DDRA,&DDRA,&DDRA,&DDRA,&DDRA,&DDRC,&DDRC,&DDRC,&DDRC,&DDRC,&DDRC,&DDRC,&DDRC,&DDRD,&DDRG,&DDRG,&DDRG,&DDRL,&DDRL,&DDRL,&DDRL,&DDRL,&DDRL,&DDRL,&DDRL,&DDRB,&DDRB,&DDRB,&DDRB,&DDRF,&DDRF,&DDRF,&DDRF,&DDRF,&DDRF,&DDRF,&DDRF,&DDRK,&DDRK,&DDRK,&DDRK,&DDRK,&DDRK,&DDRK,&DDRK};
44
   constexpr Register pinList[]  = {&PINE,&PINE,&PINE,&PINE,&PING,&PINE,&PINH,&PINH,&PINH,&PINH,&PINB,&PINB,&PINB,&PINB,&PINJ,&PINJ,&PINH,&PINH,&PIND,&PIND,&PIND,&PIND,&PINA,&PINA,&PINA,&PINA,&PINA,&PINA,&PINA,&PINA,&PINC,&PINC,&PINC,&PINC,&PINC,&PINC,&PINC,&PINC,&PIND,&PING,&PING,&PING,&PINL,&PINL,&PINL,&PINL,&PINL,&PINL,&PINL,&PINL,&PINB,&PINB,&PINB,&PINB,&PINF,&PINF,&PINF,&PINF,&PINF,&PINF,&PINF,&PINF,&PINK,&PINK,&PINK,&PINK,&PINK,&PINK,&PINK,&PINK};
45
  // #endif
46
47
  // ATtiny841 - für mich hinzugefügt
48
  #elif defined(__AVR_ATtiny841__) | defined(__AVR_ATtiny441__)
49
   constexpr uint8_t portBit[]   = {0, 1, 2, 7, 6, 5, 4, 3, 2, 1, 0};          
50
   constexpr uint8_t pinMaske[]  = {0b1,0b10,0b100,0b10000000,0b1000000,0b100000,0b10000,0b1000,0b100,0b10,0b1};
51
   constexpr Register portList[] = {&PORTB,&PORTB,&PORTB,&PORTA,&PORTA,&PORTA,&PORTA,&PORTA,&PORTA,&PORTA,&PORTA};
52
   constexpr Register ddrList[]  = {&DDRB,&DDRB,&DDRB,&DDRA,&DDRA,&DDRA,&DDRA,&DDRA,&DDRA,&DDRA,&DDRA};
53
   constexpr Register pinList[]  = {&PINB,&PINB,&PINB,&PINA,&PINA,&PINA,&PINA,&PINA,&PINA,&PINA,&PINA};
54
  // #endif 
55
56
  #else
57
      #error “This AVR type is currently not yet supported.”
58
  #endif
59
}
60
61
constexpr uint8_t getPortBit(const uint8_t pin)
62
{
63
  return portBit[pin];
64
};
65
66
constexpr uint8_t getMaske(const uint8_t pin)
67
{
68
  return pinMaske[pin];
69
};
70
71
constexpr Register getOutPort(const uint8_t pin)
72
{
73
  return portList[pin];
74
};
75
76
constexpr Register getDdrPort(const uint8_t pin)
77
{
78
  return ddrList[pin];
79
};
80
81
constexpr Register getInPort(const uint8_t pin)
82
{
83
  return pinList[pin];
84
};
85
86
// noch im Test
87
void inline __attribute__((always_inline)) digitalSwitch(uint8_t pin, uint8_t state) {
88
  if (state) *getOutPort(pin) |= getMaske(pin);
89
  else *getOutPort(pin) &= ~getMaske(pin);
90
}
91
92
/*
93
void inline __attribute__((always_inline)) pinMode(const uint8_t pin, const uint8_t function)
94
{
95
  if (function == INPUT) {  
96
    *getDdrPort(pin) &= ~getMaske(pin);
97
  }
98
  
99
  else if (function == OUTPUT) {  
100
    *getDdrPort(pin) |= getMaske(pin);
101
  }
102
  
103
  else if (function == INPUT_PULLUP) {  
104
    *getDdrPort(pin) &= ~getMaske(pin);
105
    *getOutPort(pin) |=  getMaske(pin);
106
  }
107
}
108
*/

Sketch
1
#include <PortBitList.h>
2
3
const byte pin = 13;
4
5
void setup() {
6
  pinMode(pin, OUTPUT);
7
}
8
9
void loop() {
10
11
  digitalSwitch(pin, HIGH); // 4MHz
12
  digitalSwitch(pin, LOW);  
13
  digitalSwitch(pin, HIGH);
14
  digitalSwitch(pin, LOW);
15
  digitalSwitch(pin, HIGH);
16
  digitalSwitch(pin, LOW);
17
  digitalSwitch(pin, HIGH); 
18
  digitalSwitch(pin, LOW);
19
  digitalSwitch(pin, HIGH); 
20
  digitalSwitch(pin, LOW);
21
  
22
}

von 900ss (900ss)


Lesenswert?

Veit D. schrieb:
> PortBitList.h

Wie schön dass du den Sourcecode direkt ins Posting gepackt hast. Macht 
alles viel übersichtlicher, als wenn er als Datei im Anhang ist.

von Veit D. (devil-elec)


Angehängte Dateien:

Lesenswert?

Bitte schön der Herr.

von Einer K. (Gast)


Lesenswert?

Veit, danke dass du mich hier nennst.
(der Code scheint dir ha zu gefallen)

900ss D. schrieb:
> Macht
> alles viel übersichtlicher, als wenn er als Datei im Anhang ist.

Wenn gewünscht, könnte ich auch die (ursprüngliche?) Lib hier in einen 
Anhang stellen. Da sind dann auch einige Beispiele enthalten.

von Marc (Gast)


Lesenswert?

Ein Benchmark gegenüber anderen Ansätzen wäre eventuell nicht schlecht:
https://github.com/mmarchetti/DirectIO

von Einer K. (Gast)


Lesenswert?

Benchmark?
Es gibt gleichwertige Varianten, aber keine schnelleren.
Zumindest nicht mit C++
Auch Assembler wird da keinen Takt mehr rausholen.

1
#include <CombiePin.h>
2
3
using BuiltInLed = Combie::Pin::OutputPin<LED_BUILTIN>;
4
5
BuiltInLed led;
6
7
8
int main() 
9
{
10
   led.init();
11
   while(1)
12
   {
13
     led.toggle();
14
   }
15
}
Toggelt mit 2,66MHz auf einem 16MHz Uno.
Statt digitalWrite() mit unter 60kHz

Beitrag #5722991 wurde von einem Moderator gelöscht.
von Einer K. (Gast)


Lesenswert?

gödel schrieb im Beitrag #5722991:
> Arduino Fanboy D. schrieb:
>> Auch Assembler wird da keinen Takt mehr rausholen.
>
> Du hast doch gar keine Ahnung.
Wenn du meinst....
(oder meinst du dich selber?)

OK, 2 Takte geht noch in Assembler raus zu holen.
Da springt der Compiler zu weit zurück.

> Mit Asm gehts in 1 Takt in 1 Zeile mit 1 Befehl.
Schwachfug!
Der Sprung sind 2 Takte
Das Port Register schreiben sind auch 2 Takte
Sind zusammen 4 Takte.
Da beißt keine Maus einen Faden von ab.
Auch du nicht.

Macht zusammen 6 Takte in dem C++ Programm.

> Total umständlich was ihr hier treibt.
Zeig wie es in C++ schneller geht!
(maulen kann jeder)

Beitrag #5723008 wurde von einem Moderator gelöscht.
von Einer K. (Gast)


Lesenswert?

gödel schrieb im Beitrag #5723008:
> Arduino Fanboy D. schrieb:
>> Das Port Register schreiben sind auch 2 Takte
>
> Das kommt bei raus wenn man sich in Abstraktionen verliert und sich
> immer weiter von der Hardware entfernt!
>
> Jeder Asm-Programmierer kennt den entsprechenden Register-Zugriff.
>
> Ohne weiteres kryptisches Sprach-Pallaver und um 10 Ecken denken...

Du laberst Schwachsinn!
(und merkst es noch nicht mal)

Dieses Programm erzeugt exakt den selben Code.
1
int main()
2
{
3
   DDRB = _BV(PB5);
4
   while(1)
5
   {
6
     PINB = _BV(PB5);
7
   }
8
}

Zeige wie es schneller/besser geht!

Wie schon gesagt: Maulen kann jeder!
Beim besser machen scheiden sich dann die Geister.
Dann zeigt sich das Versagen!

Los: Liefere!

Beitrag #5723018 wurde von einem Moderator gelöscht.
Beitrag #5723025 wurde von einem Moderator gelöscht.
von Einer K. (Gast)


Lesenswert?

gödel schrieb im Beitrag #5723025:
> Yalu X. schrieb:
>> auf
>>
>> sbi  0x03, 1
>>
>> reduzieren
>
> 1 Takt, 1 Zeile, 1 Instruktion...
>
> Darauf lässt sich Euer umständliches Geschreibsel eindampfen!

Damit du es mal merkst: So sieht Versagen aus
Du solltest nicht nur (nach)plappern, sondern dein Hirn einschalten.

Nicht, dass Yalu gänzlich unrecht hätte.
Das will ich gar nicht sagen!

Aber sbi ist auf mein Beispiel nicht anwendbar.
Das funktioniert nicht.

Auch ist es kein C++.
Wir reden hier über C++, und nicht über Rüben und Kartoffelsalat.

Beitrag #5723043 wurde von einem Moderator gelöscht.
von Einer K. (Gast)


Lesenswert?

gödel schrieb im Beitrag #5723043:
> Köstlich :-)
Etwas borniert heute?


Gegenbeweis:
(zum selber mitmeißeln)
1
#include <CombiePin.h>
2
3
using BuiltInLed = Combie::Pin::OutputPin<LED_BUILTIN>;
4
5
BuiltInLed led;
6
7
8
int main()
9
{
10
   led.init();
11
   while(1)
12
   {
13
     led.toggle(); // 2,667MHz
14
   }
15
}

1
int main()
2
{
3
   DDRB = _BV(PB5);
4
   while(1)
5
   {
6
     asm volatile ("sbi  0x03, 5"  :::); // 2MHz
7
   }
8
}

Beitrag #5723069 wurde von einem Moderator gelöscht.
von Einer K. (Gast)


Lesenswert?

gödel schrieb im Beitrag #5723069:
> dann haben wir das Optimum.
So sieht dein Optimum aus?


Inline Assembler ist nicht per se das Optimum.
Hier braucht es 33,333% mehr Takte als der reine C++ Code


Leider lernst du nichts, oder zu wenig, um die Angelegenheit zu 
begreifen.

von 900ss (900ss)


Lesenswert?

Jetzt sind glaube ich genug Beispiele zum Pin-Toggle vorhanden.
Noch eine Variante trägt nichts zum Thema bei. Welches ich durchaus 
interressant finde. Nur diese Beispiele sind langweilig. Auch wenn sie 
noch so toll sind.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

ja deine Klasse gefällt mir außerordentlich. Weil man merkt das sich 
jemand dabei richtig einen Kopf gemacht hat wie man trotz all der 
Kapselung keine Geschwindigkeitseinbuße hat.

Es sollte nicht unerwähnt bleiben das man mit expliziten setzen der Pins 
wieder maximal mögliche 4MHz bekommt. Soeben nochmal nachgemessen. Nicht 
das man denkt bei 2,6MHz toggle wäre Schluss.
1
#include <CombiePin.h>
2
3
using namespace Combie::Pin;
4
5
OutputPin<13> pin13;
6
7
void setup(void) 
8
{
9
  pin13.init();
10
}
11
12
void loop(void)
13
{
14
  pin13.setHigh();  // 4MHz
15
  pin13.setLow();  
16
  pin13.set(HIGH);  // 4MHz
17
  pin13.set(LOW);  
18
}

Ich finde hier kommt der Vorteil der Abstraktion voll zum tragen. Man 
muss sich einmalig mit den Registern befassen, diese gründlich prüfen 
und testen und danach kann man den Teil vergessen. Außer man macht eine 
Ergänzung. Danach erstellt man sein Pinobjekt und hantiert nur noch mit 
den Methoden dafür. Dabei wird der Anwender vor Unsinn geschützt. Man 
kann durch "Syntaxfehler" keinen Ausgang ungewollt zum Eingang machen 
und umgekehrt.

Alle anderen Libs die ich kenne, digitalWriteFast zum Bsp., erledigen 
alles intern mit #defines. Es findet keine Kapselung statt.

Deswegen muss ich Arduino Fanboy für seinen Aufwand den er getrieben 
loben.

von A. B. (Gast)


Angehängte Dateien:

Lesenswert?

@ Arduino Fanboy D

Ich kenne mich mit Arduino nicht aus. An Link zu einer Port.h &.cpp 
hätte ich Interesse.

Nach Anregung von Yalu X.(yalu) habe ich in Mcucpp::ports.h die 
Funktionen PortImplementation::Toggle() und 
PortImplementation::SetBitWiseIn() modifiziert bzw ergänzt. Damit lässt 
sich Toggle() in den Port-Registern mit sbi realisieren.

Angeheftet: AVR_toggle.lss - diesmal für ATmega328 compiliert.

von Einer K. (Gast)


Angehängte Dateien:

Lesenswert?

Veit D. schrieb:
> Es sollte nicht unerwähnt bleiben das man mit expliziten setzen der Pins
> wieder maximal mögliche 4MHz bekommt. Soeben nochmal nachgemessen. Nicht
> das man denkt bei 2,6MHz toggle wäre Schluss.
1
#include <CombiePin.h>
2
3
using BuiltInLed = Combie::Pin::OutputPin<LED_BUILTIN>;
4
5
BuiltInLed led;
6
7
8
int main()
9
{
10
   led.init();
11
   while(1)
12
   {
13
     led.toggle(); 
14
     led.toggle(); 
15
     led.toggle(); 
16
     led.toggle(); 
17
     led.toggle(); 
18
     led.toggle(); 
19
   }
20
}

Da pendelt die Anzeige meines Oszis zwischen 4 und 8MHz.
Und auf dem Bild ist die Rechteckfolge nicht mehr symmetrisch.
Die Lücken aufgrund der Schleife zeigen sich

Und Danke, für die Blumen!


A. B. schrieb:
> Ich kenne mich mit Arduino nicht aus. An Link zu einer Port.h &.cpp
> hätte ich Interesse.
Gerne, siehe Anhang.
Ist noch ein bisschen Baustelle, aber was da ist, funktioniert auch.

Eine der Schwierigkeiten/Aufgaben war, die Arduino Pin Nummerierung zu 
übernehmen, ohne sich Laufzeitnachteile/Speicherverbrauch einzuhandeln.
Als weitere Datei habe ich ASM Ausgebe der bis 8MHz  Blinkerei 
angehangen

von Wilhelm M. (wimalopaan)


Lesenswert?

Arduino Fanboy D. schrieb:

>
1
> #include <CombiePin.h>
2
> 
3
> using BuiltInLed = Combie::Pin::OutputPin<LED_BUILTIN>;
4
> 
5
> BuiltInLed led;
6
> 
7
> 
8
> int main()
9
> {
10
>    led.init();
11
>    while(1)
12
>    {
13
>      led.toggle();
14
>      led.toggle();
15
>      led.toggle();
16
>      led.toggle();
17
>      led.toggle();
18
>      led.toggle();
19
>    }
20
> }
21
> 
22
>


Der "Speicherverbrauch" dürfte bei 1 Byte RAM liegen, aber das bekommst 
Du auch noch weg!

von Einer K. (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Der "Speicherverbrauch" dürfte bei 1 Byte RAM liegen, aber das bekommst
> Du auch noch weg!


Schon längst passiert.

Der Sketch verwendet 150 Bytes (0%) des Programmspeicherplatzes. Das 
Maximum sind 32256 Bytes.
Globale Variablen verwenden 0 Bytes (0%) des dynamischen Speichers, 2048 
Bytes für lokale Variablen verbleiben. Das Maximum sind 2048 Bytes.

von Wilhelm M. (wimalopaan)


Lesenswert?

Arduino Fanboy D. schrieb:
> Wilhelm M. schrieb:
>> Der "Speicherverbrauch" dürfte bei 1 Byte RAM liegen, aber das bekommst
>> Du auch noch weg!
>
>
> Schon längst passiert.
>
> Der Sketch verwendet 150 Bytes (0%) des Programmspeicherplatzes. Das
> Maximum sind 32256 Bytes.
> Globale Variablen verwenden 0 Bytes (0%) des dynamischen Speichers, 2048
> Bytes für lokale Variablen verbleiben. Das Maximum sind 2048 Bytes.

Prima. Welcome to the club ;-)

Und jetzt machen wir den Code noch (intern) auch noch schön.

von Einer K. (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Und jetzt machen wir den Code noch (intern) auch noch schön.

Das wird noch!
Es ist ein Prozess....
Das Finale steht noch aus.

von Wilhelm M. (wimalopaan)


Lesenswert?

Arduino Fanboy D. schrieb:
> Wilhelm M. schrieb:
>> Und jetzt machen wir den Code noch (intern) auch noch schön.
>
> Das wird noch!
> Es ist ein Prozess....
> Das Finale steht noch aus.

Sehr gut! Nichts ist so lehrreich, wie das Rad neu zu erfinden!

von Einer K. (Gast)


Lesenswert?

Wilhelm M. schrieb:
> wie das Rad neu zu erfinden!

Würdest du mir die Gnade gewähren, und mir dein Rad zeigen?

von Wilhelm M. (wimalopaan)


Lesenswert?

Arduino Fanboy D. schrieb:
> Wilhelm M. schrieb:
>> wie das Rad neu zu erfinden!
>
> Würdest du mir die Gnade gewähren, und mir dein Rad zeigen?

Das habe ich oft genug hier im Forum getan, und aus verschiedenen 
Gründen kann ich das hier nicht wiederholen bzw. es mir zu mühsam, Teile 
davon zum Copy-Paste für das Forum hier herauszulösen.

Kleiner Tipp: wer constexpr, generische und variadische 
Lambda-Expressions und die damit verbundenen Themen wie template 
deduction rules, fold expressions, noexcept, IIFE, ODR, RVO und NRVO 
versteht, hat C++ insgesamt verstanden!

von Einer K. (Gast)


Lesenswert?

Ich werte das mal als Nein.

Und nee, mit einer Latte Buzzwords ist mir nun wirklich nicht gedient.
Danke für deine Mühe.

von Wilhelm M. (wimalopaan)


Lesenswert?

Arduino Fanboy D. schrieb:

> Und nee, mit einer Latte Buzzwords ist mir nun wirklich nicht gedient.
> Danke für deine Mühe.

Nun, das sind wohl kein Buzzwords, sondern es sind (bis auf eins) 
Begriffe und Konzepte aus dem C++-Standard. Oder würdest Du RAII auch 
als Buzzword bezeichnen?

von Peter D. (peda)


Lesenswert?

Ich brauche Pin toggle nur sehr selten und auch nie zeitkritisch. Daher 
bleibe ich lieber portabel und nehme ich die Standardschreibweise mit 
EXOR, auch wenn sie 100ns länger braucht.

von Thomas Z. (thozei)


Lesenswert?

Kleiner Input von mir,

ich habe mir diese LIB geforkt:

https://github.com/pichenettes/avrilx

Leider nur durch  den code dokumentiert.

Aber als Startpunkt recht gut.

Tommy

Beitrag #5723758 wurde von einem Moderator gelöscht.
Beitrag #5723768 wurde von einem Moderator gelöscht.
Beitrag #5723770 wurde vom Autor gelöscht.
Beitrag #5723771 wurde von einem Moderator gelöscht.
Beitrag #5723908 wurde von einem Moderator gelöscht.
Beitrag #5723909 wurde von einem Moderator gelöscht.
Beitrag #5723911 wurde von einem Moderator gelöscht.
Beitrag #5723912 wurde von einem Moderator gelöscht.
Beitrag #5723913 wurde von einem Moderator gelöscht.
Beitrag #5723915 wurde von einem Moderator gelöscht.
Beitrag #5723916 wurde von einem Moderator gelöscht.
Beitrag #5723917 wurde von einem Moderator gelöscht.
Beitrag #5723918 wurde von einem Moderator gelöscht.
Beitrag #5723920 wurde von einem Moderator gelöscht.
Beitrag #5723922 wurde von einem Moderator gelöscht.
Beitrag #5723923 wurde von einem Moderator gelöscht.
Beitrag #5723925 wurde von einem Moderator gelöscht.
Beitrag #5723926 wurde von einem Moderator gelöscht.
Beitrag #5723927 wurde von einem Moderator gelöscht.
Beitrag #5723928 wurde von einem Moderator gelöscht.
Beitrag #5723929 wurde von einem Moderator gelöscht.
Beitrag #5723931 wurde von einem Moderator gelöscht.
Beitrag #5723933 wurde von einem Moderator gelöscht.
Beitrag #5723934 wurde von einem Moderator gelöscht.
Beitrag #5723935 wurde von einem Moderator gelöscht.
Beitrag #5723937 wurde von einem Moderator gelöscht.
Beitrag #5723938 wurde von einem Moderator gelöscht.
Beitrag #5723939 wurde von einem Moderator gelöscht.
Beitrag #5723940 wurde von einem Moderator gelöscht.
Beitrag #5723941 wurde von einem Moderator gelöscht.
Beitrag #5723944 wurde von einem Moderator gelöscht.
Beitrag #5723945 wurde von einem Moderator gelöscht.
Beitrag #5723948 wurde von einem Moderator gelöscht.
Beitrag #5723950 wurde von einem Moderator gelöscht.
Beitrag #5723951 wurde von einem Moderator gelöscht.
Beitrag #5723953 wurde von einem Moderator gelöscht.
Beitrag #5723955 wurde von einem Moderator gelöscht.
Beitrag #5723957 wurde von einem Moderator gelöscht.
Beitrag #5723959 wurde von einem Moderator gelöscht.
Beitrag #5723960 wurde von einem Moderator gelöscht.
Beitrag #5723962 wurde von einem Moderator gelöscht.
Beitrag #5723963 wurde von einem Moderator gelöscht.
Beitrag #5723966 wurde von einem Moderator gelöscht.
Beitrag #5723968 wurde von einem Moderator gelöscht.
Beitrag #5723969 wurde von einem Moderator gelöscht.
Beitrag #5723971 wurde von einem Moderator gelöscht.
Beitrag #5723975 wurde von einem Moderator gelöscht.
Beitrag #5723977 wurde von einem Moderator gelöscht.
Beitrag #5723978 wurde von einem Moderator gelöscht.
Beitrag #5723980 wurde von einem Moderator gelöscht.
Beitrag #5723982 wurde von einem Moderator gelöscht.
Beitrag #5723983 wurde von einem Moderator gelöscht.
Beitrag #5723984 wurde von einem Moderator gelöscht.
Beitrag #5723985 wurde von einem Moderator gelöscht.
Beitrag #5723986 wurde von einem Moderator gelöscht.
von Veit D. (devil-elec)


Lesenswert?

Hallo,

darf ich Wilhelm fragen was dich an dem Code stört?
Das "schöner machen" kann so vielfältig sein.
Ich meine der Code funktioniert und der Compiler wirft keine einzige 
Warnung. Lesen kann ich den Code auch. Jetzt weiß ich auch nicht was man 
da noch anderes "schöner" machen könnte. Irgendein Beispiel?

von Wilhelm M. (wimalopaan)


Lesenswert?

Veit D. schrieb:
> Hallo,
>
> darf ich Wilhelm fragen was dich an dem Code stört?
> Das "schöner machen" kann so vielfältig sein.
> Ich meine der Code funktioniert und der Compiler wirft keine einzige
> Warnung. Lesen kann ich den Code auch. Jetzt weiß ich auch nicht was man
> da noch anderes "schöner" machen könnte. Irgendein Beispiel?

Ich habe in "CombiePin.h" hineingeschaut. Da lachten mich irgendwelche 
Monsterinitialisierer für C-Arrays an, die semantisch scheinbar auch 
eine Beziehung zueinander haben, ohne dass es der Code ausdrückt, 
gepaart mit #ifdefs, etc. Sorry, wenn ich sowas sehe, mache ich den 
Editor gleich wieder zu, auch wenn es zu funktionieren scheint.

Du hast recht: Schönheit liegt im Auge des Betrachters. In meinen Augen 
ist es (ziemlich) unschön.

Beitrag #5724474 wurde von einem Moderator gelöscht.
Beitrag #5724476 wurde von einem Moderator gelöscht.
Beitrag #5724478 wurde von einem Moderator gelöscht.
Beitrag #5724486 wurde von einem Moderator gelöscht.
Beitrag #5724489 wurde von einem Moderator gelöscht.
Beitrag #5724490 wurde von einem Moderator gelöscht.
Beitrag #5724494 wurde von einem Moderator gelöscht.
Beitrag #5724495 wurde von einem Moderator gelöscht.
Beitrag #5724497 wurde von einem Moderator gelöscht.
Beitrag #5724499 wurde von einem Moderator gelöscht.
Beitrag #5724500 wurde von einem Moderator gelöscht.
Beitrag #5724501 wurde von einem Moderator gelöscht.
Beitrag #5724503 wurde von einem Moderator gelöscht.
Beitrag #5724505 wurde von einem Moderator gelöscht.
Beitrag #5724509 wurde von einem Moderator gelöscht.
von Einer K. (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Da lachten mich irgendwelche
> Monsterinitialisierer für C-Arrays an, die semantisch scheinbar auch
> eine Beziehung zueinander haben, ohne dass es der Code ausdrückt,
> gepaart mit #ifdefs, etc.


Wie kann man die Arduinos voneinander unterscheiden, ohne #ifdef zu 
verwenden?
Das sage du mir doch mal bitte!



Zu den Arrays:

Den Compiler interessiert das sowieso nicht, wie die Arrays aussehen.
Das Kompilat ist völlig frei davon.

Die Arrays sind Maschinen generiert, aus den Header Dateien des Arduino 
Frameworks. Dort liegen sie ebenso unaufgeräumt rum. Ist nicht schön, 
hat aber Wiedererkennungswert.

Überhaupt, ist die Arduino Pin Nummerierung einerseits eine 
unausblendbare Übereinkunft, in der Arduino Welt, und andererseits folgt 
sie keinem offensichtlichen logischen System. Von daher ist diesen 
Zuordnungen auch keine absolute Schönheit ein zu einprägen. Markulatur, 
mehr geht nicht.


Es ist nicht angesagt, diese Arrays händisch zu bearbeiten.
Sie zu nutzen, ist von außerhalb nicht/kaum möglich/beabsichtigt, da in 
einem anonymen namespace untergebracht.

> Sorry, wenn ich sowas sehe, mache ich den
> Editor gleich wieder zu,
Ja dann.....

von Christoph M. (mchris)


Lesenswert?

>Überhaupt, ist die Arduino Pin Nummerierung einerseits eine
>unausblendbare Übereinkunft, in der Arduino Welt, und andererseits folgt
>sie keinem offensichtlichen logischen System.

Ursprünglich war sie dazu gedacht, die Pins den ersten Arduinos ( ich 
weiß gar nicht, welcher der erste war .. Diecimilla? ) zu abstrahieren.

Wenn man sich den Arduino-Anschlusssbuchsen anschaut, sieht man dort die 
Nummerierung. Die Idee war, dass für jede Prozessorversion die Pins an 
dieser Buchse mit der Nummer angesprochen werden können und so die 
Software unabhängig von der Hardware wird.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

@ Wilhelm, ich entnehme für mich daraus das es keine echten kritischen 
Fehler gibt in dem Sinne. Der Rest liegt im Auge des Betrachters.

@ Christoph, genau das ist der Sinn dahinter, egal welcher µC, die 
Pinnummer bleibt gleich. Macht ja auch Sinn.

von Christoph M. (mchris)


Lesenswert?

>@ Christoph, genau das ist der Sinn dahinter, egal welcher µC, die
>Pinnummer bleibt gleich. Macht ja auch Sinn.

Wobei es allerdings nur für den genormten Anschluss gut funktioniert.
Das Problem sind ja die vielen Derviate wie z.B. die ESP32 
Boardvarianten, bei denen es ja wirklich scheinbar keine Übereinkunft 
mehr gibt.

von Wilhelm M. (wimalopaan)


Lesenswert?

Arduino Fanboy D. schrieb:
> Wilhelm M. schrieb:
>> Da lachten mich irgendwelche
>> Monsterinitialisierer für C-Arrays an, die semantisch scheinbar auch
>> eine Beziehung zueinander haben, ohne dass es der Code ausdrückt,
>> gepaart mit #ifdefs, etc.
>
>
> Wie kann man die Arduinos voneinander unterscheiden, ohne #ifdef zu
> verwenden?
> Das sage du mir doch mal bitte!

Wieso Arduinos unterscheiden? Es ging um eine Klassenbibliothek für AVR!

> Zu den Arrays:
>
> Den Compiler interessiert das sowieso nicht, wie die Arrays aussehen.

Aber den Wartungsprogrammierer ;-)

> Die Arrays sind Maschinen generiert, aus den Header Dateien des Arduino
> Frameworks.

Das kann aber kein Mensch erkennen. Hast Du die da per Cut-n-Paste 
hineinkopiert???

> Dort liegen sie ebenso unaufgeräumt rum. Ist nicht schön,
> hat aber Wiedererkennungswert.

Warum erfindest Du denn das Rad neu, wenn es das in den Arduino-Libs 
alles schon gibt?

Aber dem TO ging es um AVR, nicht um Arduino-Boards.

> Überhaupt, ist die Arduino Pin Nummerierung einerseits eine
> unausblendbare Übereinkunft, in der Arduino Welt, und andererseits folgt
> sie keinem offensichtlichen logischen System. Von daher ist diesen
> Zuordnungen auch keine absolute Schönheit ein zu einprägen. Markulatur,
> mehr geht nicht.

Dann wäre es gut gewesen, mit dem Mist aufzuhören.

> Es ist nicht angesagt, diese Arrays händisch zu bearbeiten.

Hatte ich auch nicht vorgeschlagen.

von Einer K. (Gast)


Lesenswert?

Wilhelm M. schrieb:
>> Wie kann man die Arduinos voneinander unterscheiden, ohne #ifdef zu
>> verwenden?
>> Das sage du mir doch mal bitte!
>
> Wieso Arduinos unterscheiden?
Falsche Frage!
Du hast meinen Code kritisiert.
Über die Kritik rede ich!
Oder möchtest du das jetzt ausblenden?

Wilhelm M. schrieb:
> Es ging um eine Klassenbibliothek für AVR!
Nicht in deiner Kritik.
(oder gar doch?)

Wilhelm M. schrieb:
>> Die Arrays sind Maschinen generiert, aus den Header Dateien des Arduino
>> Frameworks.
>
> Das kann aber kein Mensch erkennen.
Natürlich nicht!
Steht ja auch extra dabei im Kommentar.
Kann man natürlich überlesen, wenn man es nicht liest.
Und lesen, tust du ja nach eigener Aussage eher nicht.

Wilhelm M. schrieb:
> Aber den Wartungsprogrammierer ;-)
Ja, kann sein...
Wenn der in den Arrays rum fummelt, dann ist der Code nicht mehr 
kompatibel zu den AVR Arduino Boards.
Was kann das Ziel einer Wartungsarbeit in automatisch generiertem Code 
sein?

Wilhelm M. schrieb:
> Warum erfindest Du denn das Rad neu, wenn es das in den Arduino-Libs
> alles schon gibt?
An die 60 Takte für ein digitalWrite() ... kann man nicht immer 
brauchen.
Dazu noch die Arrays und Funktionen im Flash.
Ist das Argument genug?

Wilhelm M. schrieb:
> Dann wäre es gut gewesen, mit dem Mist aufzuhören.
Durftest du dich noch nie mit einem Standard/Vereinbarung rumschlagen, 
welche dir nicht in den Kram passt?
Dann immer sofort die Flinte in den Sand gesteckt?


Außerdem, finde ich die AVR Pinbezeichnungen auch nicht viel eingängiger 
als eine Durchnummerierung, welche für jedes (der größeren) Boards gilt, 
wo Arduino drauf steht.

Schöner?
Vergleiche und entscheide selber.
1
#include "mcu/ports.h"
2
3
using namespace AVR;
4
using PortB = Port<DefaultMcuType::PortRegister, AVR::B>;
5
using led = Pin<PortB, 3>;
6
7
int main()
8
{
9
    Set<led>::output();
10
11
    led::high();
12
    while(true) {
13
        led::toggle();        
14
    }    
15
}
1
#include <CombiePin.h>
2
3
Combie::Pin::OutputPin<3> led;
4
5
int main() 
6
{
7
   led.init();
8
9
   led.setHigh();
10
   while(true) 
11
   {
12
    led.toggle();
13
   }
14
}
?




Schlussendlich:

Wilhelm M. schrieb:
> Aber dem TO ging es um AVR, nicht um Arduino-Boards.
Wieso ein Code, welcher speziell für AVR geschrieben ist, jetzt nicht 
für AVR geeignet sein soll, will ich gar nicht mehr von dir wissen.


Ja, so erlebe ich dich hier:
Kritik gerne und viel, bevorzugt von oben herab.
Konkrete Nachfragen (z.B. #ifdef) beantworten, nein Danke.

Beitrag #5725247 wurde von einem Moderator gelöscht.
Beitrag #5725248 wurde von einem Moderator gelöscht.
Beitrag #5725251 wurde von einem Moderator gelöscht.
Beitrag #5725252 wurde von einem Moderator gelöscht.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.