Forum: Mikrocontroller und Digitale Elektronik Drei kleine Fragen zur Arduino-Programmierung


von Peter B. (olduri)


Lesenswert?

Hi,

ich bin zwar alter Bastler und habe auch schon reichlich (prozedural) 
programmiert, aber nie technisch orientiert, und der Arduino (Nano) und 
"C" waren mir bisher fremd. Deshalb diese Fragen - Antworten könnten 
meine Sucherei und Rumprobiererei erheblich verkürzen.  Nun denn die 
sicherlich naiven Fragen:

1.
In der Struktur meiner loop ergibt sich ein vielfach geschachteltets "if 
.. " Um es übersichtlicher zu haben, bin ich darauf verfallen, direkt 
unterhalb der "loop" das Ganze in ein "while" zu packen:
1
 loop () { 
2
 while (true) { 
3
   if (dies) {
4
      ...
5
      continue }" 
6
   if (das) {
7
     ...
8
     continue}
9
    ... usw ...
10
 } // while
11
} // loop

einzpacken, und das geht prima. Seht ihr da irgendwelche Nachteile 
(Laufzeit!) drin?

2.
In die gleiche Richtung geht die Frage nach den Unterprogrammen, einfach 
zur Strukturierung "do_this ()" und dann irgendwo die entsprechende 
Funktion, die brauchen hier (meist) nicht mal Übergabeparams. Ist das 
Laufzeitrelevant?

3.
Die verfügbaren Datentypen sind ja ganz prima dokumentiert, auch dass 
eine Arduino-double bloß eine normale real ist, aber wie man sie in 
Arduino-C sinnvoll mischen kann, ist mir noch unklar. Ich habe hier 
bisher nur Integer-Typen von Long bis Byte angewandt, es ergab sich so 
und ist ja auch schneller, jetzt bin ich so weit, dass ich auch Reals 
einsetzten möchte. Logisch erschiene mir, dass die gesamte Rechnerei 
stets nach der Zielvariablen sich richtet.

Also Beispiel: double_var2 = long_var / double_var1
ganz ähnlich, mit Rundung wäre: long_var2 = long_var1 / double_var + 
0.5;

Hier dürfte nicht double_var1 abgeschnippelt und dann die Division mit 
ebenfalls abgeschnippeltem  Rest mit der long_var verwurstelt werden. 
Ich brauche also eine Type-Umwandlung für die long_var, also so etwas 
wie "double(long_var)". Mir ist nicht klar, wie ich das sicher 
hinbekomme (außer wenn ich es in Einzelschritten mit expliziten 
Wertzuweisungen mache, aber das kanns doch nicht sein.)
Vermutlich würde ich das in irgendwelchen dicken C-Büchern finden, aber 
ob das dann auch für den Arduino gilt?

LG,
(und vielen Dank für eventuelle Antworten. Wenn ich weiter bin, stelle 
ich auch gerne mal das ganze Projekt vor, falls Interesse besteht.)

: Bearbeitet durch User
von Markus (Gast)


Lesenswert?


von Einer K. (Gast)


Lesenswert?

Peter B. schrieb:
> bin ich darauf verfallen, direkt
> unterhalb der "loop" das Ganze in ein "while" zu packen

Hmm..

Ich halte das für überflüssig, da loop() sowieso in genau einer solchen 
While Schleife dauernd aufgerufen wird.
Auch funktioniert dann serialEvent() nicht mehr.


Später, bei andere Arduinos, ESP ö.ä. kann dir das derbe auf die Füße 
fallen, da diese durchaus noch einigen Kram neben loop() erledigen 
müssen.

Mantra:
Keine lang laufenden Schleifen!
(es sei denn, du weißt genau, was du da tust)

von W.S. (Gast)


Lesenswert?

Peter B. schrieb:
> In der Struktur meiner loop ergibt sich ein vielfach geschachteltets "if
> .. " Um es übersichtlicher zu haben, bin ich darauf verfallen, direkt
> unterhalb der "loop" das Ganze in ein "while" zu packen:
>  loop () {
>  while (true) {
>    if (dies) {
>       ...
>       continue }"
>    if (das) {
>      ...
>      continue}
>     ... usw ...
>  } // while
> } // loop
> einzpacken, und das geht prima.

Mir kommt das ein bissel kraus und unverständlich vor. Was ist beim 
Arduino denn:

loop() {...}

Ich vermute mal, das ist ein Teil der Dauer-Schleife in main, wo er 
immerzu drin herumkreiselt und eigentlich sollte er dort verschiedene 
Dinge verrichten, von denen das Reagieren auf Events nur ein Teil ist.

Also sinngemäß etwa so:
1
int main (void)
2
{ InitialisiereDies();
3
  InitialisiereDas();
4
5
mainloop:
6
  MacheDies();
7
  MacheDas();
8
  if (Event1vorhanden) BehandleEvent1();
9
  if (Event2vorhanden) BehandleEvent2();
10
  goto mainloop;
11
}

Ist das so? Oder meinst du irgend etwas Anderes?

W.S.

von Einer K. (Gast)


Lesenswert?

W.S. schrieb:
> Ist das so?

Die original AVR Arduino main():
1
int main(void)
2
{
3
  init();
4
5
  initVariant();
6
7
#if defined(USBCON)
8
  USBDevice.attach();
9
#endif
10
  
11
  setup();
12
    
13
  for (;;) {
14
    loop();
15
    if (serialEventRun) serialEventRun();
16
  }
17
        
18
  return 0;
19
}

Da sieht man deutlich, dass die Schleife in main die loop() funktion 
dauernd aufruft.
Damit ist die Schleife in loop() sinnfrei, bzw. kontraproduktiv.

Gerade auch, wenn man es mit ESP o.ä. zu tun bekommt.

von N.N. (Gast)


Lesenswert?

zu erstens und zweitens:

zuerst würde ich das einfach so schreiben, hier frühzeitig zu optimieren 
wäre falscher Ansatz - an dieser Stelle gibt es wenig Code, Ram und 
Laufzeit zu verbessern, bzw hat am wenigsten Einfluss auf das Ergebnis.

Die eine "machdas()" funktion - ob das wirklich ein overhead wird, hängt 
ja vom compiler ab. Eventuell macht der die Funktion "inline()", oder er 
lässt sie, damit die große loop keinen longjump oder sowas machen muss.

Wegen Fließkomma Zahlen:
Ich caste da gerne sehr viel rum, und führe temporäre Variablen ein, 
damit absolut klar ist, was ich will.
Beispiel
1
 uint32_t mess_int = messwert();
2
 uint32_t parameter_int = parameter();
3
 float mess_float = (float)(mess_int);
4
 float divisor = (float)(parameter_int);
5
 float ergebnis = mess_float/divisor;
6
 machwasdamit(ergebnis);

Stück für Stück also, für Lesbarkeit - und der Compiler macht den Rest.

Aber: ich meide floats und Teilen durch eine Variable wie die Pest - 
einmal im code, vergrößert sich dieser um ein paar kilobyte, und es ist 
arg langsam. Die bithacks helfen hier oft: 
https://graphics.stanford.edu/~seander/bithacks.html

von Markus (Gast)


Lesenswert?

>Aber: ich meide floats und Teilen durch eine Variable wie die Pest -
>einmal im code, vergrößert sich dieser um ein paar kilobyte, und es ist
>arg langsam.

So langsam sind die gar nicht:
https://www.avrfreaks.net/comment/2503681#comment-2503681

von Chris K. (Gast)


Lesenswert?

Anstelle der ganzes If If If solltest du dir mal die Switch Anweisung 
anschauen. Dann für die Cases auch keinen ellenlangen Code schreiben, 
sondern alles schön in Funktionen verpacken. So wird das Programm 
übersichtlich.

von Oliver S. (oliverso)


Lesenswert?

N.N. schrieb:
> Die bithacks helfen hier oft:
> https://graphics.stanford.edu/~seander/bithacks.html

Diese bithacks ind inzwischen 15 Jahre alt, daß ist in dem Kontext älter 
als die Steinzeit.

Folge doch einfach deinem eigenem Ratschlag:

N.N. schrieb:
> Stück für Stück also, für Lesbarkeit - und der Compiler macht den Rest.

Du glaubst gar nicht, was die Compiler inzwischen für "bithacks" 
draufhaben.

Floats sollte man dann verwenden, wenn man sie braucht. Vor Angst aber 
auch integer -Divisionen vermeiden, ist pathologisch.

Oliver

von Axel S. (a-za-z0-9)


Lesenswert?

Peter B. schrieb:
> In der Struktur meiner loop ergibt sich ein vielfach geschachteltets "if
> .. " Um es übersichtlicher zu haben, bin ich darauf verfallen, direkt
> unterhalb der "loop" das Ganze in ein "while" zu packen:
>
>
1
 loop () {
2
>  while (true) {
3
>    if (dies) {
4
>       ...
5
>       continue }"
6
>    if (das) {
7
>      ...
8
>      continue}
9
>     ... usw ...
10
>  } // while
11
> } // loop
>
> einzpacken, und das geht prima. Seht ihr da irgendwelche Nachteile
> (Laufzeit!) drin?

Ich scheitere ehrlich gesagt schon daran, einen Vorteil zu erkennen. 
Ist dir auch klar, daß du im Arduino Paradigma die loop() Funktion 
wieder verlassen mußt? Ich sehe da erstmal nur eine Endlosschleife und 
nirgendwo eine Stelle, wo die auch verlassen wird. Wenn du in Arduino an 
den Anfang der Endlosschleife willst, mußt du einfach nur die loop() 
funktion mit return verlassen:
1
loop() {
2
  if (dies) {
3
    machwas();
4
    return;
5
  }
6
  if (jenes) {
7
    machwasanderes();
8
    return;
9
  }
10
  ...
11
}

Wenn du Arduino-typisch mit den Funktionen setup() und loop() 
programmierst, dann solltest du dich diesem Paradigma auch unterwerfen. 
Oder - IMHO besser - du läßt das links liegen und schreibst einfach 
deine eigene main() Funktion mit der üblichen Endlosschleife.

> In die gleiche Richtung geht die Frage nach den Unterprogrammen, einfach
> zur Strukturierung "do_this ()" und dann irgendwo die entsprechende
> Funktion, die brauchen hier (meist) nicht mal Übergabeparams. Ist das
> Laufzeitrelevant?

Auf der Maschinenebene wird der Aufruf einer Funktion mit (R)CALL und 
RET realisiert. Das braucht dann entsprechend zwei Maschinenbefehle 
länger und ein paar Bytes auf dem Stack. Das ist seltenst relevant. 
Außerdem kann der Compiler auch selbständig entscheiden, ob er statt des 
Sprungs zur Funktion anderswo lieber gleich den Funktionsrumpf an der 
Stelle des Aufrufs einfügt (Inlining). Kürzer gesagt: das ist sinnlose 
Mikrooptimierung. Sieh lieber zu, daß dein Code lesbar ist.

> ...
> Vermutlich würde ich das in irgendwelchen dicken C-Büchern finden, aber
> ob das dann auch für den Arduino gilt?

Arduino ist keine Programmiersprache. Das ist C++ mit einer 
vordefinierten main() und einer fetten Standardbibliothek. Inklusive ein 
paar schrägen typedefs bzw. #defines.

Wenn du schon programmieren kannst, wäre es überlegenswert, den Arduino- 
Ballast über Bord zu werfen und gleich bare-metal zu programmieren. Also 
deine eigene main() Funktion, Datentypen von C++ und Portzugriffe nicht 
per digitalWrite() & Co, sondern direkt auf die IO-Register.

von Peter B. (olduri)


Lesenswert?

Danke für die Antworten!

Mit der While-Schleife ging es mir lediglich darum, das "continue" 
zwecks Übersichtlichkeit einsetzen zu können. Das funktioniert nicht 
direkt in der main loop.

Zum Verständnis:
Es handelt sich um eine Drehzahlregelung für einen riemengetriebenen 
Plattenspieler. Das DC-Motörchen liefert 6 Impulse pro Umdrehung, mithin 
6 Interrupts. Die Soll-Zeit ist ca. 28000 micros() pro Umdrehung. Ich 
machs mal in Pseudo-Code.

Ihn öfter als einmal pro Umdrehung regeln zu wollen, ist komplett 
Quatsch. Die ISR liefert also eine unsigned long t_ist und setzt einen 
Zähler.

In der loop wird also zuerst der Zähler abgefragt, wenn noch nicht 
erreicht, dann ist sie erst mal fertig.

Sonst: prüfen, ob viel zu schnell null-Spannung geben, neuen soll-Wert 
setzten, fertig
Viel zu langsam, vollgas, sonst oben, fertig,

Wenn er hier ankommt, ist er im Range - also dann prop. Abweichung 
berechnen, Motorspannung schreiben, ist-Wert umspeichern, fertig. Mehr 
ist nicht, aber es muss ziemlich schnell gehen.

Jetzt ist es also eine reine Prop-Steuerung, und ich bin froh, darauf 
gekommen zu sein. Aufgrund der Plattentellermasse gibt es einen prima 
Gleichlauf, aber aus sportlichen Gründen und um vielleicht noch 1/10 % 
besseren Gelichlauf rauszuholen hätte ich es gerne zur PID-Regelung 
aufgebohrt, was wohl dann nur mit REALS geht. Deshalb war noch die 3. 
Frage.

Grüße, P.

von Peter B. (olduri)


Lesenswert?

So, ich sehe gerade, es gibt noch etliches an Antworten - vielen Dank, 
ich glaub, da ist manches aufschlussreiches für mich drin.

muss jetzt allerdings mal andere Sachen machen - bis später!

von Einer K. (Gast)


Lesenswert?

Der erste Teil ist wohl ein einfacher endlicher Automat.
Der benötigt keine Schleifen oder continue.


Es wäre klüger, in Nebenläufigkeiten zu denken.

Wenn deine Zeitmessung sowieso Interrupt gesteuert arbeitet, hast du 
dort schon die erste Nebenläufigkeit.

Der PID Algorithmus, der zweite Faden.

von Theor (Gast)


Lesenswert?

@ Peter

Zu 1.

a) Man muss wissen, dass die loop-Funktion in der Arduino-Umgebung eine 
besondere Eigenheit hat. Es ist nämlich vorgesehen, dass diese von einer 
übergeordneten Funktion zyklisch aufgerufen wird. In jedem Zyklus wird 
aber in der übergeordneten Funktion noch anderes erledigt.

Falls Du in der loop-Funktion eine Endlos-Schleife hinschreibst, die nie 
verlassen wird, verhinderst Du damit, dass diese Andere getan wird.
Siehe dazu die Arduino-Dokumentation.

b) Was die Übersichtlichkeit dieser Schreibweise betrifft, ist das 
sicher Ansichtssache. Ich selbst finde das "unübersichtlich". 
Insbesondere das "continue", (dass mir übrigens in freier Wildbahn 
äusserst selten begegnet) erregt meine Aufmerksamkeit. Es entfällt aber 
sowieso, da Du, wie erwähnt, eine Endlosschleife an dieser Stelle nicht 
verwenden darfst.

Wenn man meinen Einwand von 1.a. berücksichtigt, würde der Code so 
aussehen können:
1
loop () { 
2
   if (dies) {
3
      ...
4
   } 
5
   if (das) {
6
     ...
7
   }
8
    ... usw ...
9
} // loop

Der Knackpunkt ist eigentlich, ob sich die Bedingungen "dies" und "das" 
gegenseitig ausschliessen oder nicht.

Sieht man von der ursprünglich vorhandenen while-Schleife ab, hat das 
"continue" die Wirkung, dass, falls "dies" wahr war, die Bedingung "das" 
nicht mehr geprüft wird.

Falls also "das" auch wahr sein kann, wenn "dies" wahr ist, dann ist das 
ursprüngliche Verhalten auch mit einem "else" zu erreichen.
1
loop () { 
2
   if (dies) {
3
      ...
4
   } 
5
   else if (das) {
6
     ...
7
   }
8
    ... usw ...
9
} // loop

Andererseits: Falls "das" nie wahr sein kann, falls "dies" wahr ist, 
kann das else entfallen.

2. Tatsächlich sind Funktionen, - auch ohne Parameter -, 
laufzeitrelevant.
Allerdings gibt es einerseits Gegenmittel ("inline") als auch 
grundsätzliche Überlegungen dazu.

Arduino ist ohnehin nicht für wirkliche Echtzeitanwendungen geeignet. 
Das soll nicht heissen, dass man nicht, durch entsprechende 
Programmstruktur auch im Arduino-Kontext eine größere Geschwindigkeit 
erreichen kann.
Aber das Ganze ist an sich langsam(er), als Code ohne den 
Arduino-Overhead.
Wenn man also dahin kommt, dass die Laufzeit ein Problem wird, dann 
gewinnt man mehr - mehr Laufzeit-Reserven -, wenn man sich von Arduino 
abwendet.

3. An sich ist, was Deine Frage betrifft, das beim Arduino verwendete 
C++, "normales", standardisiertes C++. Der Unterschied sind eine ganze 
Reihe von vordefinierten Funktionen und implizitem Verhalten (das was 
parallel zu loop() geschieht).

Um Dein Beispiel aufzugreifen, wird die long variable vor der Division 
implizit in ein double umgewandelt - auch wenn Du das nicht 
hinschreibst. Die Frage ist, ob Du das an der Stelle willst.

Es gibt auch Möglichkeiten Umwandlungen ausdrücklich hinzuschreiben. Das 
nennt sich "cast" (was man mit "umgiessen" - im Sinne von: "in eine 
andere Form giessen" übersetzen könnte).

Die Regeln sind an sich nicht sehr umfangreich, aber im Einzelfall 
manchmal nicht vorhergesehene Resultate, falls man es versäumt sich die 
Wertebereiche und die Auflösung vorher zu überlegen.

Ich kann an dieser Stelle nur empfehlen, sich intensiv mit einem C-Buch 
zu beschäftigen. Das Thema ist einfach zu umfangreich um es hier 
vollständig zu erklären.


Persönlich möchte ich Dir, - obwohl ich damit potentiell einen Disput 
provoziere -, ernsthaft davon abraten, mit Arduino anzufangen, falls Du 
den Wunsch hast langfristig komplexere Projekte zu realisieren.

Die Zielgruppe sind eigentlich Menschen, die vergleichsweise einfache 
Abhängigkeiten und Reaktionen darauf beschreiben wollen. Dazu bietet die 
Arduino-Umgebung eine ganze Reihe von vordefinierten Funktionen, welche 
den Umgang mit uCs vereinfachen sollen und daher Komplexität verbergen, 
die aber mit gewissen, für den ernsthaft arbeitenden Entwickler 
inakzeptablen Konsequenzen, wie z.B. minderer Flexibilität und minderer 
Transparenz verbunden sind.

Das ist, wiegesagt, meine persönliche Meinung und wer Arduino verwenden 
will soll das tun. Es ist selbstverständlich nicht unmöglich, mit 
Arduino zu beginnen und dann sein Wissen zu vertiefen. Ich halte es aber 
für einen unnötigen Umweg, auf dem so manche Überraschung lauert. Die 
oben erwähnte Tatsache über die loop-Funktion ist dafür ein schon fast 
prominentes Beispiel.

von Einer K. (Gast)


Lesenswert?

Peter B. schrieb:
> Vermutlich würde ich das in irgendwelchen dicken C-Büchern finden, aber
> ob das dann auch für den Arduino gilt?

Natürlich!
Abgesehen von ein paar AVR spezifischen Besonderheiten, ist das ein 
vollwertiges C++
z.Zt. C++11
Aufbohrbar auf C++17

von W.S. (Gast)


Lesenswert?

N.N. schrieb:
> Die eine "machdas()" funktion - ob das wirklich ein overhead wird, hängt
> ja vom compiler ab.

Nein, sondern davon, wie gut man seine Firmware strukturiert. Ich bin 
überhaupt kein Freund davon, daß man alles und jedes in main 
hineinpackt. Stattdessen sollte man separate Units schreiben, die sich 
jeweils nur einer (begrenzten) Aufgabe widmen.

Und diese Units werden ein jeder für sich übersetzt und folglich gibt es 
in main auch kein Inline, sondern einen tatsächlichen Funktionsaufruf. 
Wenn man den nicht vollstopft mit Argumenten, dann ist der Aufruf auch 
kein merklicher Overhead. Aber man erreicht mit dem Modularisieren 
eines: Klarheit und Übersichtlichkeit.


N.N. schrieb:
> Wegen Fließkomma Zahlen:
> Ich caste da gerne sehr viel rum, und führe temporäre Variablen ein,
> damit absolut klar ist, was ich will.

Das ist zwar nett gedacht, aber das wilde Herumcasten ist etwas, das man 
besser bleiben lassen sollte. Merke: Casts sollte man sparsam verwenden 
und eben deshalb nur dort, wo sie tatsächlich vonnöten sind. Es sind 
nämlich Anweisungen an den Compiler, etwas entgegen seiner Meinung zu 
tun - und damit ist man selber verantwortlich für den Murks, der dabei 
herauskommen kann.


> Beispiel
>  uint32_t mess_int = messwert();
>  uint32_t parameter_int = parameter();
>  float mess_float = (float)(mess_int);
>  float divisor = (float)(parameter_int);
>  float ergebnis = mess_float/divisor;
>  machwasdamit(ergebnis);
>
> Stück für Stück also, für Lesbarkeit - und der Compiler macht den Rest.

Lesbarkeit?
Wenn ich so etwas lese, dann kommt vor mein geistiges Auge der Spruch 
"Knüppel aus dem Sack!". Es scheint in C-Kreisen eine penetrante Marotte 
zu sein, immer alles zusammenziehen zu wollen. Am liebsten 
Typdeklaration, Variable dazu und Aufruf einer Funktion obendrauf noch 
dazu in einer Zeile.

Wenn deine Funktion messwert sauber definiert ist, also z.B.

unsigned long messwert (void) {....}

und du deren Ergebnis deiner ebenfalls sauber definierten Funktion

void machwasdamit (float F) {...}

zuweisen willst, dann geht das direkt und ohne Herumgecaste.
1
 unsigned int i;
2
 float A, B;
3
4
 A = messwert();
5
 i = parameter();
6
 if (i)
7
 { B = i;
8
   machwasdamit(A/B);
9
 }
10
 else
11
 { Hey_DivByNull();
12
 }


W.S.

von MaWin (Gast)


Lesenswert?

Peter B. schrieb:
> 1.

Das while ist Blödsinn, exakt das steht um die loop.

Peter B. schrieb:
> Ist das Laufzeitrelevant?

Klar kostet ein Unterprogrammaufruf Zeit (und viel schlimmer: stack).

Wenn ein Unterprogramm nur von 1 Stelle aus aufgerufen wird, ist es 
Unsinn.

Ein lokaler Block (also { und code und } ) wäre sinnvoller wenn es eh 
keine Parameter gibt. Oder gleich den alten code an der Aufrufstelle 
hinschreiben.
Dann kann der Compiler auch besser optimieren.

Man könnte die Funktion mit inline qualifizieren.

Peter B. schrieb:
> 3.

Gleitpunktzahlen sind auf Arduino VIEL langsamer als Integer. So lange 
mna also kann, bleibt man bei int und long, und bildet damit ggf. feste 
Nachkommastellen ab (Cent statt Euro). Gleitpunkt ist immer ein 
Notbehelf.

von Stefan F. (Gast)


Lesenswert?

Axel S. schrieb:
> Oder - IMHO besser - du läßt das links liegen und schreibst einfach
> deine eigene main() Funktion mit der üblichen Endlosschleife.

Das wird bei den ESP Modulen nicht funktionieren.

> Wenn du schon programmieren kannst, wäre es überlegenswert, den Arduino-
> Ballast über Bord zu werfen und gleich bare-metal zu programmieren.

Ja. Entweder programmiert man in Arduino so, wie das dort vorgesehen 
ist, oder man lässt es komplett bleiben.

von Einer K. (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Ja. Entweder programmiert man in Arduino so, wie das dort vorgesehen
> ist, oder man lässt es komplett bleiben.

Heute wieder voll auf Schwarz/Weiß Sicht eingestellt?

Zum Glück ist es jedem Individuum überlassen, ob oder welche der Arduino 
Komponenten verwendet werden.

von Markus (Gast)


Lesenswert?

>Gleitpunktzahlen sind auf Arduino VIEL langsamer als Integer. So lange
>mna also kann, bleibt man bei int und long, und bildet damit ggf. feste
>Nachkommastellen ab (Cent statt Euro). Gleitpunkt ist immer ein
>Notbehelf.

Das kommt darauf an. Für seine Anwendung ist die Geschwindigkeit von 
Float mehr als ausreichend und macht die Sache deutlich einfacher.

>So langsam sind die gar nicht:
>https://www.avrfreaks.net/comment/2503681#comment-2503681

Falls man dem Link vertrauen darf, liegt die Rechenzeit für eine 
Float-Multiplikation bei 5us.

von Axel S. (a-za-z0-9)


Lesenswert?

W.S. schrieb:
> N.N. schrieb:
>> Die eine "machdas()" funktion - ob das wirklich ein overhead wird, hängt
>> ja vom compiler ab.
>
> Nein, sondern davon, wie gut man seine Firmware strukturiert.

> ... Units werden ein jeder für sich übersetzt und folglich gibt es
> in main auch kein Inline, sondern einen tatsächlichen Funktionsaufruf.

Du solltest ab und zu mal unter deinem Stein hervor kriechen und dir die 
Welt anschauen. Die hat sich seitdem verändert. (avr-)gcc kann schon 
eine ganze Weile LTO (link time optimzation). Und damit funktioniert 
Inlining auch über die Grenzen von Translation Units.

> ... man erreicht mit dem Modularisieren
> eines: Klarheit und Übersichtlichkeit.

Dem kann ich allerdings nur beipflichten. Einer der Hauptgründe, warum 
man überhaupt höhere Programmiersprachen erfunden hat (statt weiterhin 
alles in Assembler zu schreiben) ist, daß Programme in Hochsprache 
lesbarer sind. Oder in deinen Worten: klarer und übersichtlicher. 
Dadurch tendentiell auch fehlerärmer, mindestens jedoch wartbarer.

Diesen Vorteil sollte man nicht aufgeben, um ein paar CPU-Zyklen an 
potentiell unwichtigen Stellen einzusparen.

von Stefan F. (Gast)


Lesenswert?

Arduino Fanboy D. schrieb:
> Zum Glück ist es jedem Individuum überlassen, ob oder welche der Arduino
> Komponenten verwendet werden.

Ja stimmt. Die Leute dürfen dann auch gerne hier ihre nicht 
funktionierenden Code-Fragmente zeigen und um Hilfe bitten. 
Insbesondere, wenn sie die wie oben die loop() missverstanden haben.

Hast du schon einmal ESP Module mit Arduino programmiert?

von Peter B. (olduri)


Lesenswert?

Hi allerseits,

erst mal vielen Dank für Eure Antworten. Sie haben meine Fragen 
weitgehend beantwortet und auch eine Menge, die ich gar nicht gestellt 
habe. Und außerdem eine, sagen wir mal, gewisse Spannbreite von 
Meinungen gezeigt, zwischen denen ich mir was aussuchen kann.

Ich will jetzt nicht auf einzelne Beiträge eingehen. Aber eines noch: 
Ich finde, dass der Arduino-Kram durchaus für Leute wie mich gemacht 
wurde.

Habe also keine Lust, auf die "Maschinenebene" hinabzusteigen, auch 
wenns schneller geht.

Man muss sich auch beim Hobby nicht alle möglichen Baustellen antun.

Bei dem Versuch, meinem Arduino Nano beizubringen, analogWrite auf mehr 
als 8 bit auszugeben, gescheitert, anscheinend geht es nicht. (Waren im 
Netz auch keine Beispiele für den Nano zu finden, obwohl der Atmega 328 
das können sollte, hab ich irgendwo gelesen) Ist aber, glaube ich, auch 
nicht nötig, die Regelspannung pendelt sowieso um deutlich mehr als 
1/255)

Meine Kenntnisse sind heute Steinzeit. Besonders in Pascal habe ich (in 
1-Mann-Projekten als freelancer, wie man das heute nennt) einiges 
gemacht, auch schön verkauft damals, aber unter DOS, immer schön 
strukturiert und ohne Objekte, die fingen dann während der Laufzeit 
meiner Sachen so langsam mit Turbo5.5 an. Es war 
kaufmännisch-verwaltende Software. Dann ging die Reise anderswohin. 
Deshalb die vielleicht etwas naive Fragerei.


Bis jetzt ist der Arduino auch schnell genug (und genug Platz), um 
nebenbei auch noch per Serial.print etwas an Ausgaben zu machen, was ich 
natürlich per #define nur zum Testen eineschalte. Ich dachte nur, wenn 
ich meinen P-Regler nun auf PID aufsatteln will, könnte es knapp werden.

Ich habe auch recht gründlich den PID-Blog auf brettbeauregard.com 
angeschaut, der benutzt für seine Arduino-PID-Lib hauptsächlich double, 
leider ist das Ding für meine Zwecke so nicht anwendbar. Aber die 
Erläuterungen schon.

So, das wärs jetzt erst mal, was mich betrifft.

Wenn Ihr jetzt sagt, wir wollen UNBEDINGT das Ding sehen, wo die 
Arduinos drin stecken, dann verlinke ich meine 43-Foto-Schau, ansonsten 
will ich mich diesbezüglich nicht vordrängeln.

Grüße, Peter B.

von Peter B. (olduri)


Lesenswert?

Stefan ⛄ F. schrieb:

> ... Die Leute dürfen dann auch gerne hier ihre nicht
> funktionierenden Code-Fragmente zeigen und um Hilfe bitten.
> Insbesondere, wenn sie die wie oben die loop() missverstanden haben.
>
> Hast du schon einmal ESP Module mit Arduino programmiert?

Da muss ich doch noch mal: das mit der loop hab ich schon verstanden, 
und für nicht funktionierende Code-Fragmente brauche ich auch keine 
Hilfe.
Was ein ESP Modul ist, weiß ich allerdings nicht, und dein Beitrag macht 
auch keine Lust, danach zu suchen.

von Stefan F. (Gast)


Lesenswert?

Peter B. schrieb:
> Wenn Ihr jetzt sagt, wir wollen UNBEDINGT das Ding sehen, wo die
> Arduinos drin stecken, dann verlinke ich meine 43-Foto-Schau

Ich glaube fast alle hier gucken sich gerne Fotos von den Projekten 
anderer an. Für mich gilt das auf jeden Fall!

von Stefan F. (Gast)


Lesenswert?

Peter B. schrieb:
> Was ein ESP Modul ist, weiß ich allerdings nicht, und dein Beitrag macht
> auch keine Lust, danach zu suchen.

ESP8266: 32bit Mikrocontroller mit 160 MHz, mit WLAN und typischerweise 
4 Megabyte Programmspeicher

Kosten aber weniger als 3 Euro!

ESP32: 32bit Mikrocontroller mit 240 MHz, WLAN, Bluetooth, Ethernet. 
Einige Modelle haben Dual-Core Prozessoren.

Kosten weniger als 10 Euro.

Und beide sind mit Arduino programmierbar. man muss da aber die loop() 
richtig nutzen: Immer nur kurz etwas machen und dann die loop verlassen, 
damit der WLAN/Bluetooth Treiber unter der Haube oft genug aufgerufen 
wird.

von Gerald K. (geku)


Lesenswert?

Peter B. schrieb:
> In die gleiche Richtung geht die Frage nach den Unterprogrammen, einfach
> zur Strukturierung "do_this ()"

Verwende INLINE Funktionen. Diese sind schneller, da der Code direkt 
eingesetzt wird.

von Stefan F. (Gast)


Lesenswert?

Gerald K. schrieb:
> Verwende INLINE Funktionen. Diese sind schneller, da der Code direkt
> eingesetzt wird.

Wobei der C Compiler kleine Funktionen bereits automatisch in inlined.

von Einer K. (Gast)


Lesenswert?

Gerald K. schrieb:
> Verwende INLINE Funktionen. Diese sind schneller, da der Code direkt
> eingesetzt wird.

Arduino Standard Optimierung ist -Os.
Der Kompiler wird also im Rahmen seiner Möglichkeiten abwägen, ob er die 
Dinge Inline macht, oder nicht. Ob du inline hinschreibst, oder auch 
nicht, ist dabei recht egal.

Das C++ inline Statement ist nur eine Empfehlung an den Kompiler. 
Keinesfalls eine zwingende Aufforderung. Den Zwang kann man über none 
Standard Attribute ausüben.

Peter B. schrieb:
> Bei dem Versuch, meinem Arduino Nano beizubringen, analogWrite auf mehr
> als 8 bit auszugeben, gescheitert, anscheinend geht es nicht. (Waren im
> Netz auch keine Beispiele für den Nano zu finden, obwohl der Atmega 328
> das können sollte, hab ich irgendwo gelesen)
Richtig erkannt.
analogWrite() kann das nicht.

Du könntest mit Timer1 bis auf 16Bit PWM hoch.
Dazu müsstest du aber das Datenblatt des ATMega328p aufmerksam lesen.

von Wolfgang (Gast)


Lesenswert?

Arduino Fanboy D. schrieb:
> Auch funktioniert dann serialEvent() nicht mehr.

Zwischendurch rechtzeitig mal ein Aufruf von yield() hilft dagegen 
ungemein.

von Einer K. (Gast)


Lesenswert?

Wolfgang schrieb:
> Arduino Fanboy D. schrieb:
>> Auch funktioniert dann serialEvent() nicht mehr.
>
> Zwischendurch rechtzeitig mal ein Aufruf von yield() hilft dagegen
> ungemein.
No!
Es gibt keine Beziehung zwischen serialEvent() und yield() beim Arduino 
Nano.


yield() ist als weak deklariert.
Existiert also gar nicht wirklich beim Nano. Zumindest keine 
Implementierung, welche Einfluß auf serialEvent() hätte.

Wenn man yield() nutzen möchte, muss man es sich selber bauen.

von Peter B. (olduri)


Lesenswert?

Stefan ⛄ F. schrieb:
> Ich glaube fast alle hier gucken sich gerne Fotos von den Projekten
> anderer an. Für mich gilt das auf jeden Fall!

Als dann, gerne.

Werde das aber nur ne bestimmte online halten, aus gewissen Gründen.
Über die Sinnhaftigkeit, sich heute einen Dreher zu drechseln, brauchen 
wir aber nicht zu reden.

Viel Spaß!

http://jodre.de/dreherdrei/index.html

von Bildbetrachter (Gast)


Lesenswert?

Peter B. schrieb:
> Viel Spaß!
>
> http://jodre.de/dreherdrei/index.html

Faszinierend wie manche Leute voraussetzen dass der Bildschirm
der Leute die seine Fotos anschauen wollen / sollen genau so breit
oder breiter ist als der eigene.

Intelligentere / professionellere Lösungen würden hier einen
automatischen Umbruch vorsehen.

OMG!

von Stefan F. (Gast)


Lesenswert?

Bildbetrachter schrieb:
> Faszinierend wie manche Leute voraussetzen dass der Bildschirm
> der Leute die seine Fotos anschauen wollen

Es ist halt nicht jeder ein erfahrener Webdesigner. Ich bin sicher, dass 
du auch nicht alles perfekt kannst.

Peter B. schrieb:
> Viel Spaß!
> http://jodre.de/dreherdrei/index.html

Danke für die Fotos, ich finde zusammen mit den Erläuterungen sie sehr 
interessant! Jetzt klinke ich mich mal für eine Stunde aus, habe was zu 
lesen bekommen :-)

von Einer K. (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Danke für die Fotos, ich finde zusammen mit den Erläuterungen sie sehr
> interessant!

Zustimmung!

Würde nicht auf eine solche Idee kommen, dennoch schön.

von Oliver S. (oliverso)


Lesenswert?

Stefan ⛄ F. schrieb:
> Gerald K. schrieb:
>> Verwende INLINE Funktionen. Diese sind schneller, da der Code direkt
>> eingesetzt wird.
>
> Wobei der C Compiler kleine Funktionen bereits automatisch in inlined.

Und vor allem, weil der gcc seit Generationen inline einfach ignoriert, 
weil er es eh besser weiß und auch macht.

Oliver

von c-hater (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:

> Ja. Entweder programmiert man in Arduino so, wie das dort vorgesehen
> ist, oder man lässt es komplett bleiben.

So isses. Und ich würde mich jederzeit für die zweite Option 
entscheiden...

von Einer K. (Gast)


Lesenswert?

c-hater schrieb:
> Stefan ⛄ F. schrieb:
>
>> Ja. Entweder programmiert man in Arduino so, wie das dort vorgesehen
>> ist, oder man lässt es komplett bleiben.
>
> So isses. Und ich würde mich jederzeit für die zweite Option
> entscheiden...


Die Arduino Umgebung ermöglicht die Programmierung in C, C++ und 
Assembler.
Das ist die aktuelle Vorgabe.
So ist es Vorgesehen.

Solltest du was anderes meinen, könntest du das nochmal überdenken.

Am Rande:
Andere Sprachen kommen in nächster Zeit dazu.

von Stefan F. (Gast)


Lesenswert?

Arduino Fanboy D. schrieb:
> Solltest du was anderes meinen, könntest du das nochmal überdenken.

Es ging darum, die loop() zu umgehen.

von Einer K. (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Arduino Fanboy D. schrieb:
>> Solltest du was anderes meinen, könntest du das nochmal überdenken.
>
> Es ging darum, die loop() zu umgehen.

Wenn einem die loop() Funktion nicht schmeckt, lässt man sie weg!
Setzt statt dessen eine eigene main() ein.
Und dabei ist es, wie schon gesagt, egal ob diese in C, C++ oder
Assembler geschrieben ist.

Man ist dann aber für alles selber verantwortlich.
z.B. delay() und millies() funktioniert dann nicht mehr.
Dann ist Schluss mit einigen Arduino Komfort Funktionen

von leo (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Es ging darum, die loop() zu umgehen.

Mein dzt. Arduino-Programm (Uhr, Thermometer, LCD) hat keine 
loop()-Funktion.
s. https://github.com/prampec/arduino-softtimer

"When you use SoftTimer you do not implement the "loop" function of the 
Arduino. All your code will run event driven, all processes running 
asynchronous, no more blocking code...".

Das Hauptgeruest schaut so aus:
1
Task base_t(1000,  base_f); // incr now all 1 s
2
Task dtm_t(5000,  dtm_f);   // disp time    5 s
3
...
4
SoftTimer.add(&base_t);
5
...
leo

von Stefan F. (Gast)


Lesenswert?

Arduino Fanboy D. schrieb:
> Wenn einem die loop() Funktion nicht schmeckt, lässt man sie weg!
> Setzt statt dessen eine eigene main() ein.

Das ist wie auch andere bereits schrieben der Moment, wo einige 
Funktionen ausfallen.

> Man ist dann aber für alles selber verantwortlich.

Das ist genau das Gegenteil vom Sinn des Arduino Frameworks.

Nochmal die Frage: Hast du Erfahrung in der Programmierung von ESP 
Modulen mit Arduino?

von Einer K. (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Nochmal die Frage: Hast du Erfahrung in der Programmierung von ESP
> Modulen mit Arduino?
Versuchst du mich gerade in aller Öffentlichkeit für blöd zu verkaufen?

Merke dir:
Wenn du meinst, in mir einen Idioten vor dir zu haben, dann bist du bei 
mir genau an der richtigen Adresse.
Das ignoriere ich noch nicht einmal!


--------


Arduino Fanboy D. schrieb:
> Später, bei andere Arduinos, ESP ö.ä. kann dir das derbe auf die Füße
> fallen, da diese durchaus noch einigen Kram neben loop() erledigen
> müssen.

von c-hater (Gast)


Lesenswert?

Arduino Fanboy D. schrieb:

> Die Arduino Umgebung ermöglicht die Programmierung in C, C++ und
> Assembler.

Letzteres nicht wirklich. Gerade die Tricks, die wirklich was bewirken 
könnten, sind nur mit so viel Aufwand möglich, dass es sehr viel 
einfacher ist, den Kram gleich komplett in Assembler umzusetzen.

Aber selbst das ist leider keine Option mehr, wenn proprietäre Blobs 
involviert sind, denen man nicht einfach z.B. die Benutzung bestimmter 
Resourcen abgewöhnen könnte. Das betrifft insbesondere 
Arduino-Rucksack-Blähungen wie z.B. die ESP* oder Teensy*.

Wer sowas benutzt, muss sich einfach klarmachen, dass er nicht die volle 
Kontrolle über die Hardware hat. Aber natürlich: die typische Zielgruppe 
von Arduino hat die ja sowieso nie, diesen Arduidioten ist das aber wohl 
auch vollkommen Wurscht...

von Stefan F. (Gast)


Lesenswert?

Also lautet die Antwort wohl: nein
Den Dieter Nuhr zitiere ich jetzt mal nicht.

An alle Anfänger hier:

Der Arduino Fanboy hat viele Jahre Programmiererfahrung, vermutlich 
länger als es Arduino gibt. Deswegen scheut er sich nicht, am Framework 
vorbei zu arbeiten. Dadurch entstehende Probleme kann er zweifellos 
selbst beheben.

Anfängern rate ich allerdings davon ab, am Arduino Framework vorbei zu 
programmieren, um zeitraubende Probleme zu vermeiden. Man erspart sich 
dann auch blöde Kommentare vom Arduino Fanboy.

von Einer K. (Gast)


Lesenswert?

c-hater schrieb:
> Letzteres nicht wirklich. Gerade die Tricks, die wirklich was bewirken
> könnten, sind nur mit so viel Aufwand möglich, dass es sehr viel
> einfacher ist, den Kram gleich komplett in Assembler umzusetzen.

Eigentlich wollte ich sagen:
Stefan ⛄ F. schrieb:
> Das ist genau das Gegenteil vom Sinn des Arduino Frameworks.

Zum Glück, hast nicht du die Definitionshoheit.
Und der C Hasser auch nicht.
Der hat sich doch bestimmt noch nie damit befasst, außer Bullshit zu 
predigen.


Das mache ich jetzt aber nicht, und sage dir:

c-hater schrieb:
> Gerade die Tricks, die wirklich was bewirken
> könnten, sind nur mit so viel Aufwand möglich, dass es sehr viel
> einfacher ist, den Kram gleich komplett in Assembler umzusetzen.
Natürlich muss man das in Assembler umsetzen, wenn man das in Assembeler 
umsetzen möchte.

Was daran jetzt komplizierter sein soll, als in anderen Umgebungen 
leuchtet mir nicht ein.
Man wird oft eine *.h Datei erzeugen müssen, um anderen (z.B. *.c und 
*.cpp) Dateien die Assembler Funktionen(Labels) und Daten bekannt zu 
machen.

Den Assembler Code stopft man in eine *.S Datei, und fertig ist die 
Laube.

Das ist nicht komplizierter als mit anderen IDEs.
Eher noch einfacher.
Nix Makefile o.ä. editieren.

Kann dir auch gerne mal ein rudimentäres Arduino Assembler Projekt 
zeigen.
Wenn du es sehen möchtest.

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.