Forum: Mikrocontroller und Digitale Elektronik Schulnotenbewertung eines Arduino-Programms


von Ralph S. (jjflash)


Angehängte Dateien:

Lesenswert?

Weil es mir jetzt einfach keine Ruhe läßt. Es geht darum, dass ein 
Lehrling, 2 Lehrjahr, Ausbildungsberuf Physiklaborant in der 
Berufsschule die Aufgabenstellung hatten, mittels Arduino ein 
Lauflichprogramm zu erstellen.

Die originale Aufgabenstellung habe ich gerade nicht parat, aber sie 
mußten Arduino dafür verwenden, dürfen (weil wohl nicht besprochen 
wurde) keine Interrupts verwenen und die LEDs sind über ein 
Schieberegistermodul angeschlossen, für das sie eine Beschreibung 
erhalten hatten und vorgestellt wurde, wie dem Schieberegister Werte 
zugewiesen werden. Jetzt ist mein Lehrling - aus meiner Sicht der Dinge 
- (weit) über dem, was ein 18-jähriger im 2. Lehrjahr können muß, er 
interessiert sich hier sehr stark für Arduino und auch grundsätzlich 
Mikrocontroller. Grundsätzlich erkennt man von seiner Art und Weise 
schon auch meine Handschrift in der Programmierung wie ich ihm manche 
Dinge gezeigt habe, bspw. das Zerlegen in kleine Funktionen und 
insbesondere auch das Kommentieren des Codes.

Das Lauflicht sollte über einen Trimmer in der Ablaufgeschwindigkeit 
geändert werden können und über einen 2 pol. Dipschalter 4 verschiede 
Auswahlmuster wählbar sein.

Im Anhang könnt ihr sehen, was er in der Schule abgeliefert hat und ganz 
ehrlich hat es mich "beeindruckt", wie er as gelöst hat (ich bin ganz 
sicherich nicht mehr von einem LED-Laulicht beeindruckt).

Grundsätzlich hat er etwas gemacht, von dem er wahrscheinlich die 
Fachbegriffe gar nicht kennt. Aus meiner Sicht der Dinge hat er so etwas 
wie ein "event-pollinggetriebenes" Programm geschrieben, das aus Sicht 
der I/O Devices (Trimmer, DIP-Schalter, LED) noch nicht einmal 
blockierend ist.  Änderungen am Trimmer oder eine Änderung an den 
DIP-Schaltern erzeugen relativ unmittelbar Änderungen im Programmablauf.

Ich habe viele Lauflichtprogramme von Lehrlingen gesehen, aber das hier 
ist mit Abstand das beste (für mich).

Mich würde jetzt echt interessieren, welche Note aus einer 
"Lehrersichtweise" hier angemessen ist?

PS: natürlich werden jetzt wieder die ewigen Nörgler und Trolle 
aufschlagen, aber auf eine neutrale, sachliche Aussage freue ich mich!
von Rahul D. (rahul)


Lesenswert?

Ralph S. schrieb:
> Mich würde jetzt echt interessieren, welche Note aus einer
> "Lehrersichtweise" hier angemessen ist?

Die kommt auf die Aufgabenstellung, den Lehrstoff und die Erwartung des 
Dozenten an.
Wenn die Erwartung (aka "Musterlösung") ge- oder übertroffen wurde, 
sollte es eine 1 geben.

Ralph S. schrieb:
> Physiklaborant
Erfordert der schon eine (Fach-) Hochschulreife?

Von den meisten meiner Mitschülern meine Berufschulklasse hätte ich man 
sowas nicht bekommen.
Die Quellcode-Formatierung (inkl. Kommentare) finde ich vorbildlich, 
nachdem ich schon von Quellcode von E-Technik-Mastern pflegen durfte, 
die an sowas gar kein Interesse hatten.
von Stefan S. (chiefeinherjar)


Lesenswert?

1
  sr.setvalue(laufl_prog[i + 1], 1);    // Ausgabe eines Leuchtmusters

Warum i+1? Denn so wird das erste Element (mit Index 0) nie angesprochen 
und die Array-Grenze überschritten. Oder sehe ich da was falsch?
von Rahul D. (rahul)


Lesenswert?

Stefan S. schrieb:
> Warum i+1? Denn so wird das erste Element (mit Index 0) nie angesprochen
> und die Array-Grenze überschritten. Oder sehe ich da was falsch?
1
len = laufl_prog[0];
übersehen?
Da mit Pointern auf (unterschiedlich lange) Arrays gearbeitet wird, 
braucht man die Längeninformation explizit.
von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Stefan S. schrieb:
> Denn so wird das erste Element (mit Index 0) nie angesprochen
Dort wird die Länge herausgeholt:
1
    len = laufl_prog[0];

> die Array-Grenze überschritten.
Nein, weil das Pascal-String-mäßig ja explizit über diesen Längeneintrag 
an Index 0 abgehandelt wird.

Ralph S. schrieb:
> Ich habe viele Lauflichtprogramme von Lehrlingen gesehen, aber das hier
> ist mit Abstand das beste (für mich).
Sieht gut aus. Es wurden einige Gimmicks verwendet, die durchaus als 
"fortgeschritten" eingestuft werden können.

Allerdings muss der Schreiber noch die "Potenz" aus dem Potentiometer 
raushalten ;-)
- https://de.wikipedia.org/wiki/Potentiometer
: Bearbeitet durch Moderator
von Stefan S. (chiefeinherjar)


Lesenswert?

Ahhhh Danke für die Korrektur!

Rahul D. schrieb:
> Stefan S. schrieb:
>> Warum i+1? Denn so wird das erste Element (mit Index 0) nie angesprochen
>> und die Array-Grenze überschritten. Oder sehe ich da was falsch?
> len = laufl_prog[0];
> übersehen?

Tatsächlich übersehen! Danke!
von Ralph S. (jjflash)


Lesenswert?

Rahul D. schrieb:
> Ralph S. schrieb:
>> Physiklaborant
> Erfordert der schon eine (Fach-) Hochschulreife?

erfordert "nur Realschulabschluß, obwohl dort einige Abiturienten und 
Fachhochschulreife Auszubildende dabei sind.

Lothar M. schrieb:
> Allerdings muss der Schreiber noch die "Potenz" aus dem Potentiometer
> raushalten ;-)
> - https://de.wikipedia.org/wiki/Potentiometer

Dass man "Potentiometer" jetzt mit "z" schreibt.... tut nicht nur dir 
weh.

Diese Schularbeit wurde - mir komplett unverständlich - mit einer 3,2 
bewertet und ich bin am Überlegen, ob ich da beim Lehrer "vorstellig" 
werden sollte. Auch um dem Auszubildenden zu zeigen, dass ich nicht 
hinter der Lehrerentscheidung stehe.

Nach meinen Kriterien hätte ich 1,5 gegeben ... auch wegen 
"Flüchtigkeitsfehler" in den Kommentaren:
1
     ADC / 3 = 341; 341 + maxspeed (40) = 381
2
3
     Rueckgabewerte je nach Potenziometereinstellung 0..381
denn es hat eine Spannweite von 40..381, zudem ein Fehler eines 
Funktionsprototypen:
1
uint8_t io_init(void)
2
{
3
  pinMode(dipkey_0, INPUT_PULLUP);
4
  pinMode(dipkey_1, INPUT_PULLUP);
5
  pinMode(speedctrl, INPUT);
6
}

Das hätte "void io_init(void)" heißen müssen...
von Rolf (rolf22)


Lesenswert?

Lothar M. schrieb:
> Mich würde jetzt echt interessieren, welche Note aus einer
> "Lehrersichtweise" hier angemessen ist?

Wie schon andere gesagt haben: Es kommt darauf an, was GENAU die Aufgabe 
war und was gekonnt werden hätte sollen. Das ist also ein subjektiver 
Maßstab, den können wir hier mangels Wissen nicht anlegen. Rein objektiv 
wäre es für einen "richtigen" Programmierer Schulnote 4 minus - 
vorausgesetzt, es läuft wenigstens richtig, was ich bezweifle.
Allerdings muss so ein Azubi nicht das können, was ein richtiger 
Programmierer kann. Anders gesagt: Relativ gesehen mag dieser Azubi gut 
sein, absolut gesehen ist er es nicht.

Nur ein paar Punkte:
Insbesondere die Routine polled_delay() ist misslungen: Es werden dort 
zwei Dinge vermischt, und zwar so unübersichtlich, dass man nicht leicht 
erkennen kann, was da bewirkt wird.

Der zweifache Aufruf von dipkey_get() (einer sichtbar in loop, einer 
unsichtbar in loop) macht das dann noch schlimmer. Mag sein, dass es mit 
diesem und anderen Tricks funktioniert, aber gut im Sinne einer sauberen 
Programmierung ist das nicht. Es sind "schmutzige" Tricks.

Das Arduino-Paradigma (setup vs. loop) ist auch nicht eingehalten, die 
Initialisierungen am Anfang von loop() gehören da nicht hin.

Zur Unübersichtlichkeit:
Deswegen ist es wohl auch passiert, dass der Programmierer selbst nicht 
gemerkt hat, dass die Variablen dipkey_status zwar ausgelesen, ihr aber 
im gesamten Programm nirgendwo ein Wert zugewiesen wird. Läuft das 
Programm denn so überhaupt richtig?
von Rolf (rolf22)


Lesenswert?

Ralph S. schrieb:
> Dass man "Potentiometer" jetzt mit "z" schreibt.... tut nicht nur dir
> weh.

Das ist ein Fachwort und darf deshalb laut Duden weiterhin mit 't' 
geschrieben werden. (Ich schreibe das auch mit 't'.)
von Alexander (alecxs)


Lesenswert?

Ralph S. schrieb:
> Diese Schularbeit wurde - mir komplett unverständlich - mit einer 3,2
> bewertet

Vielleicht weil die Urheberschaft der dafür genutzten KI nicht mit 
angegeben wurde?
von Rahul D. (rahul)


Lesenswert?

Ralph S. schrieb:
> Dass man "Potentiometer" jetzt mit "z" schreibt.... tut nicht nur dir
> weh.

Das macht man jetzt für die GenZ so.

Ralph S. schrieb:
> Nach meinen Kriterien hätte ich 1,5 gegeben ... auch wegen
> "Flüchtigkeitsfehler" in den Kommentaren:

Ich hatte den Quellcode nur überflogen und fand die Aufgabe gut (2) 
gelöst.

Rolf schrieb:
> Das Arduino-Paradigma (setup vs. loop) ist auch nicht eingehalten, die
> Initialisierungen am Anfang von loop() gehören da nicht hin.

Die der static-Variablen?

Alexander schrieb:
> Vielleicht weil die Urheberschaft der dafür genutzten KI nicht mit
> angegeben wurde?

Wäre die Software per KI entstanden, deren Verwendung aber augeschlossen 
worden und der Lehrer hätte es rausgefunden / nachgewiesen, wäre 
sicherlich keine 3,2, sondern 5 oder 6 als Note rausgekommen.
Nicht jeder geht den einfachsten Weg...
Beitrag #8043417 wurde vom Autor gelöscht.
von Norbert (der_norbert)


Lesenswert?

Rahul D. schrieb:
> Die der static-Variablen?

Bei zweien davon ist static unnötig.
von Ralph S. (jjflash)


Lesenswert?

Rolf schrieb:
> Rein objektiv
> wäre es für einen "richtigen" Programmierer Schulnote 4 minus -
> vorausgesetzt, es läuft wenigstens richtig, was ich bezweifle.
> Allerdings muss so ein Azubi nicht das können, was ein richtiger
> Programmierer kann.

Das Ding läuft sogar sehr gut und auf eine Drehbewegung beim 
Potentiometer (jetzt mit "t") reagiert das Programm sofort mit einer neu 
eingestellten Geschwindigkeit. Gleiches gilt für das Erfassen der 
Dipschalter.

Ich werde heute abend mal die originale Aufgabenstellung hier posten, 
allerdings ist diese wirklich sehr "allgmeine" gehalten und da kann man 
alles hineininterpretieren.

Rolf schrieb:
> Das Arduino-Paradigma (setup vs. loop) ist auch nicht eingehalten, die
> Initialisierungen am Anfang von loop() gehören da nicht hin.

Arduino-Paradigma hin- oder her. Für die Initialisierungen hier 
(last_mode und i) hätte er diese global machen müssen um sie nach setup 
zu verfrachten. auch nicht schön. Grundsätzlich lasse ich mich zu 
Arduino-Paradigmen nicht wirklich aus, aber ich gebe dir recht.

Rolf schrieb:
> Deswegen ist es wohl auch passiert, dass der Programmierer selbst nicht
> gemerkt hat, dass die Variablen dipkey_status zwar ausgelesen, ihr aber
> im gesamten Programm nirgendwo ein Wert zugewiesen wird. Läuft das
> Programm denn so überhaupt richtig?

Natürlich liest er das aus. Der "Trick" seiner polled_delay ist der, 
dass er den letzten Status der DIP-Schalter mit übergibt (hier als 
"mode" bezeichnet, was ich in der Bezeichnung inkonsistent finde) und in 
der delay dann selbst als dipkey_status. hier wäre es besser gewesen 
einheitliche Namen zu wählen.

Und ja, wie oben bereits gesagt läuft das sogar sehr gut. Seine 
polled_delay soll mehr oder weniger einen Eventstatus zurückliefern: 
0x80 für korrekt durchgelaufene Delay, jeder andere Wert eine neue 
Schalterkombination im Vergleich beim Eintritt in die Delayroutine, 
damit direkt darauf eingegangen werden kann. :-) er hat sogar eine 
Funktionsbeschreibung seines Programms gemacht, wie und warum das so 
funktioniert.

Alexander schrieb:
> Vielleicht weil die Urheberschaft der dafür genutzten KI nicht mit
> angegeben wurde?

Bei einigen Teilen war ich dabei wie er das geschrieben hat. Wenn er 
hier KI (chatgpt ?) eingesetzt hat, dann aber garantiert nicht für 
dieses Programm. Ich habe die Originalanforderung der Schule bei chatgpt 
eingegeben, es kam ein Programm heraus, das zum einen schon syntaktisch 
nicht korrekt war und zum aderen einen komplett anderen Ablauf hat. 
Schon gar nicht, dass im Grunde ein "Leuchtmusterabspielprogramm" dabei 
herausgekommen wäre.

Rahul D. schrieb:
> Wäre die Software per KI entstanden, deren Verwendung aber augeschlossen
> worden und der Lehrer hätte es rausgefunden / nachgewiesen, wäre
> sicherlich keine 3,2, sondern 5 oder 6 als Note rausgekommen.
> Nicht jeder geht den einfachsten Weg...

Hätte er es abschließend durch eine KI gejagt (ich habe das gemacht), 
dann ist eines der ersteren Teile was chatgpt bemängelt, dass es bei: 
uintt8_t dipkey_get(void) richtigerweise void dipkey_get(void) heißen 
muß und der Kommentar für den runspeed_get falsch ist. Ein paar weitere 
Kleinigkeiten auch und dann hätte er das sicherlich selbst noch 
geändert. Ich möchte meine Hand nicht ins Feuer legen, dass er vllt. 
auch chatgpt bemüht hat, aber sicherlich hat chatgpt das Programm so 
nicht erzeugt!
von Ralph S. (jjflash)


Lesenswert?

Norbert schrieb:
> Bei zweien davon ist static unnötig.

Hm, ich sehe nur "event" als unnötig statisch an, alle anderen brauchen 
das doch (ich kann mich aber auch täuschen).
von Norbert (der_norbert)


Lesenswert?

Ralph S. schrieb:
> Arduino-Paradigma hin- oder her. Für die Initialisierungen hier
> (last_mode und i) hätte er diese global machen müssen um sie nach setup
> zu verfrachten. auch nicht schön. Grundsätzlich lasse ich mich zu
> Arduino-Paradigmen nicht wirklich aus, aber ich gebe dir recht.

Das sind teilweise Variablen, welche erhalten bleiben müssen und daher 
in loop() goldrichtig aufgehoben sind.
Weil sie auch nur dort sichtbar sein sollen.

Nur eben nicht alle der als static ausgewiesenen Variablen.
Das macht's entweder unschön oder unüberlegt. je nach Betrachtungsweise.
von Norbert (der_norbert)


Lesenswert?

Ralph S. schrieb:
> Norbert schrieb:
>> Bei zweien davon ist static unnötig.
>
> Hm, ich sehe nur "event" als unnötig statisch an, alle anderen brauchen
> das doch (ich kann mich aber auch täuschen).

mode ebenfalls. Wird gleich ein paar Zeilen darunter überschrieben.
von 900ss (900ss)


Lesenswert?

Rolf schrieb:
> Das Arduino-Paradigma (setup vs. loop) ist auch nicht eingehalten, die
> Initialisierungen am Anfang von loop() gehören da nicht hin.

Wo steht denn geschrieben, dass alles, also auch Variablen in setup() 
initialisiert werden müssen?

Die Variablen die nur in einer Funktion genutzt werden (hier in loop()) 
sind als lokale Variablen dort besser aufgehoben weil es weniger 
Verwirrung stiftet. Die hätten sonst, wie schon angemerkt, global sein 
müssen. Und das wäre eher ein "Mangel" für mein dafürhalten.

Ja, in Arduino ist viel global was in meinen Augen nicht zu den guten 
Eigenschaften dieser Umgebung zählt.

Rolf schrieb:
> Rein objektiv wäre es für einen "richtigen" Programmierer Schulnote 4
> minus - vorausgesetzt, es läuft wenigstens richtig, was ich bezweifle.

Ja, eine 4 minus hätte diesen Azubi ganz sicher motiviert, es das 
nächste Mal besser zu machen. :(

Ihm eine Anerkennung zeigende Note zu geben und ihm erklären wo die 
Schwächen seines Programmes liegen sind mit Sicherheit zielführender. 
Bzw. ihn selber nochmal nachdenken lassen, ob er nicht dich 
Verbesserungspotenzial findet. Um sich beim nächsten mal nochmal genau 
anzusehen was man ihm dann bei dieser Aufgabe erklärt und gezeigt, oder 
er selbst erkannt hat.

Eine 4 minus dafür, empfinde ich als Ohrfeige. Erinnert mich an meinen 
Opa.

Eine eins ist es sicher nicht. Aber eine 4 minus noch viel weniger.

Ich sehe es auch besser als drei an.
Auch gut zu strukturieren braucht Übung und muss man lernen. Und es sind 
gute Ansätze in der Struktur drin.
: Bearbeitet durch User
von Loco M. (loco)


Lesenswert?

Ralph S. schrieb:
> Diese Schularbeit wurde - mir komplett unverständlich - mit einer 3,2
> bewertet und ich bin am Überlegen, ob ich da beim Lehrer "vorstellig"
> werden sollte. Auch um dem Auszubildenden zu zeigen, dass ich nicht
> hinter der Lehrerentscheidung stehe.

Solange du die Gründe des Lehrers nicht kennst, würde ich den 
Auszubildenden heraushalten. Also persönliches Gespräch suchen, und wenn 
du dann mit der Entscheidung nicht einverstanden bist, kannst du dich 
immer noch hinter deinen Azubi stellen.

Auch wenn vielleicht keine KI genutzt wurde, der vergessene Kommentar 
"Schrittmotormuster" deutet an, dass es da eine Vorlage gab. In meinen 
Augen nicht unbedingt etwas negatives, vorhandenen Code sinnvoll für 
eigene Zwecke nutzen zu können ist auch eine wichtige Fähigkeit.
1
uint8_t lauf_bmp1[] = {16, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff,   //
2
                           0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00 };
3
4
uint8_t lauf_bmp2[] = { 4, 0x33, 0x66, 0xcc, 0x99 };                         // Schrittmotormuster
5
6
uint8_t lauf_bmp3[] = { 8, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x81 };
von Bruno V. (bruno_v)


Lesenswert?

Jetz mal ehrlich: Wenn das Programm richtig gut funktioniert, sollte das 
allein schon eine 2 sein (Genauer gesagt: 80%). Schlechter als 3 kann es 
eigentlich nur sein, wenn es irgendwo hakt und das nicht im Vorfeld 
beschrieben wurde, z.B. eine nicht sofortige Reaktion auf Zeitänderung.

Ob das jetzt 1 oder 2 ist, kann nur das Klassenniveau zeigen. Wenn die 
einen Super Lehrer haben und alle liefern sowas ab, dann halt eher 2.

Es gibt eigentlich nur 2 Gründe für die schlechte Note: Der Lehrer 
konnte das Programm aus dem Tritt bringen oder der Azubi konnte eine 
Zeile nicht erklären.

Wenn es das nicht war, gehe ruhig zum Lehrer und frage ihn, worauf genau 
Du bei Deinem Ausbilden künftig achten solltest.


Für die Nicht-Laboranten: Programmierung ist nur ein Teilbereich von 
ganz vielen anderen: Quasi so, wie SPS-Programmierung beim Schlosser 
oder CNC-Programmierung beim Schreiner.
: Bearbeitet durch User
von Sheeva P. (sheevaplug)


Lesenswert?

Ralph S. schrieb:
> Weil es mir jetzt einfach keine Ruhe läßt.

In dipkey_get(): geschweifte Klammern plus Einrückung des Code hinter 
den ifs. Ja, kann man weglassen, macht man aber nicht, meine Entwickler 
würden dafür einen zwischen die Hörner bekommen. Zudem braucht { keine 
eigene Zeile, sowas macht man nur bei Chefs die die Leistung von 
Entwicklern anhand von LOC beurteinen wollen. Für solche Idioten will 
man aber eh nicht arbeiten und dann ist es auch wieder egal, ob man 
Zeilen schindet oder nicht.
von Veit D. (devil-elec)


Lesenswert?

Hallo,

ich möchte jetzt nicht unhöflich sein, aber die Handschrift von Ralph 
sieht man im Code. Ich hatte es schon einmal woanders erwähnt, dass 
static Variablen in main(), hier loop(), sinnlos sind, sie sind 
praktisch gesehen global und sollte demzufolge auch global sein.

> Aus meiner Sicht der Dinge hat er so etwas
> wie ein "event-pollinggetriebenes" Programm geschrieben, das aus Sicht
> der I/O Devices (Trimmer, DIP-Schalter, LED) noch nicht einmal
> blockierend ist.

Doch, es ist leider blockierend geschrieben. Die Funktion polled_delay() 
blockiert immer eine gewisse Zeit. Vielleicht unterhalb der 
Wahrnehmungsgrenze, aber blockiert. Die Arduino IDE bringt dafür ein 
Bsp. mit - BlinkWithoutDelay.
1
int runspeed_get(void)
2
const int speedctrl= A0;
Sollte beides unsigned int sein.

Die Mustersteuerung hätte man mit enum + switch als Ablaufsteuerung 
erschlagen können. Aber dafür gibt es mehrere Möglichkeiten. Bin nicht 
so der Zeigertyp, nur wenn es nicht anders geht.

Die "frei liegende" i Inkrementierung gefällt mir auch nicht.

Schulnote vergebe ich keine, weil ich nicht weiß welchen Wissenstand der 
Azubi haben muss bzw. sollte. Nur da es in der Schule eine Aufgabe war, 
muss vorher dahingehend Wissen vermittelt wurden sein. Auch hier wissen 
wir nicht welches. Das kann um Welten besser sein wie der Lehrer 
erwartet muss aber nicht. Mit 3,5 wohler weniger wie erwartet. Kann ich 
jedoch nicht beurteilen. Wie sehen die Programme der anderen Azubis aus 
mit welcher Benotung?

Ich sage einmal so. Wenn es funktioniert und die Blockierung geduldet 
wird, ist es schon deutlich besser was sonst so im Arduino Forum 
reinflattert. Allerdings weiß ich auch, dass man die erwähnten 
Feinheiten erst später im Grundsatz versteht, wenn man sich näher damit 
beschäftigt. Ist als nicht Lehrer für mich schwer zu benoten. Zudem wie 
gesagt paar unschöne Eigenarten vom Ausbilder mit reinspielen. Ich muss 
das leider so sagen.
von Nemopuk (nemopuk)


Lesenswert?

Beklage dich nicht beim Lehrer. Das sollte der Schüler besser selbst 
tun. Idealerweise nicht als Klage formuliert, sondern erfragen, wie es 
dem Lehrer besser gefallen hätte.
von Veit D. (devil-elec)


Lesenswert?

Hallo,

fast vergessen. Das define muss weg.
1
#define maxspeed   40

Weil wenn man vorher sowas schreibt
1
const int dipkey_0= 4;
2
const int dipkey_1= 3;
und danach mit define weitermacht, dann wird es komisch.
Natürlich auch alles unsigned.
: Bearbeitet durch User
von Ralph S. (jjflash)


Lesenswert?

Loco M. schrieb:
> Auch wenn vielleicht keine KI genutzt wurde, der vergessene Kommentar
> "Schrittmotormuster" deutet an, dass es da eine Vorlage gab.

Nein, die gab es nicht. Ich hatte ihm erzählt, das ein einfacher 
Schrittmotor mit diesem Lauflicht als Bitmustergenerator verwendet 
werden könnte und darauf hin wurde das Bitmuster von ihm hinzugefügt 
(schmunzeln muß, jetzt verteidige ich ihn auch hier). Allerdings ist das 
gut zu sehen (oder interessant), dass nicht alle ihn für so gut wie ich 
halten.

Veit D. schrieb:
> Ist als nicht Lehrer für mich schwer zu benoten. Zudem wie
> gesagt paar unschöne Eigenarten vom Ausbilder mit reinspielen. Ich muss
> das leider so sagen.

Kann ich so akzeptieren, ich bin schon auch kritikfähig.
von Rolf (rolf22)


Lesenswert?

Ralph S. schrieb:
>> Deswegen ist es wohl auch passiert, dass der Programmierer selbst nicht
>> gemerkt hat, dass die Variablen dipkey_status zwar ausgelesen, ihr aber
>> im gesamten Programm nirgendwo ein Wert zugewiesen wird. Läuft das
>> Programm denn so überhaupt richtig?
>
> Natürlich liest er das aus.

??? Du hast meinen obigen Text nicht richtig gelesen.   :-(

Der Variablen "dipkey_status" wird nirgendwo explizit ein Wert 
zugewiesen. Somit ist ihr Wert undefiniert und/oder konstant. In beiden 
Fällen ist es unsinnig, auf ihren Wert lesend zuzugreifen: Wenn 
undefiniert, dann ist es per se sinnlos, wenn konstant, dann ist die 
Variable überflüssig.

Im selben Zusammenhang: Auch die Variable "last_mode" ist unsinnig 
verwendet. Nach dem allerersten Auslesen der Dip-Schalter ist die 
"letzte" Schalterstellung später logischerweise(!) niemals mehr 
unbekannt. Trotzdem hat der Programmierer den Wert der Variablen 
zwischendurch völlig unnötig wieder auf "unbekannt" gesetzt (last_mode = 
0xff). Unlogisch und ein ganz schmutziger Trick, der keinerlei Vorteile 
bringt, wohl aber die Übersichtlichkeit und Funktions-Sicherheit 
verschlechtert.

Falls man es wirklich braucht verwendet man eine zusätzliche 
bool-Variable dafür ("DipHasChanged"), die man in der Funktion X setzt, 
in der die Schalterstellung eingelesen wird - und nirgendwo anders. So 
wird die Logik übersichtlich und der Code sauber.
von Rolf (rolf22)


Lesenswert?

900ss schrieb:
> Eine 4 minus dafür, empfinde ich als Ohrfeige. Erinnert mich an meinen
> Opa.
>
> Eine eins ist es sicher nicht. Aber eine 4 minus noch viel weniger.

Du hast richtig gelesen? Für eine "richtigen" Programmierer ist es 4 
minus, für den Azubi aus einem anderen Fach nicht.
von Helmut H. (helmuth)


Lesenswert?

Rolf schrieb:
> Der Variablen "dipkey_status" wird nirgendwo explizit ein Wert
> zugewiesen. Somit ist ihr Wert undefiniert und/oder konstant. In beiden
> Fällen ist es unsinnig, auf ihren Wert lesend zuzugreifen
1
uint8_t polled_delay(uint8_t dipkey_status)
dipkey_status in polled_delay wird beim Aufruf aus loop übergeben, hat 
daher den Wert von mode. Ihr Wert ist nie undefiniert und es ist normal, 
lesend darauf zuzugreifen.
: Bearbeitet durch User
von Veit D. (devil-elec)


Lesenswert?

Ralph S. schrieb:

> Kann ich so akzeptieren, ich bin schon auch kritikfähig.
Da bin beruhigt.  :-)

Mir wäre es jedoch wichtiger, wenn man über die vermeintliche 
Nichtblockierung nicht hinweg sehen würde. Deshalb nochmal der Hinweis, 
dass polled_delay() blockierend wirkt.
1
uint8_t polled_delay(uint8_t dipkey_status)
2
{
3
  Serial.println("polled");
4
  
5
  uint32_t start = millis();
6
  uint32_t runtime;
7
  uint8_t dipkeys;
8
9
  while (1)
10
  {
11
    dipkeys = dipkey_get();         
12
    if (dipkeys != dipkey_status)
13
    {
14
      Serial.println("return A");
15
      return dipkeys;
16
    }
17
18
    runtime = millis() - start;       
19
                                                              
20
    if (runtime >= runspeed_get())
21
    {
22
      Serial.println("return B");
23
      return 0x80;                   
24
    }
25
    Serial.println("while");
26
  }
27
}
1
18:06:58.525 -> polled
2
18:06:58.525 -> while
3
18:06:58.525 -> while
4
18:06:58.525 -> while
5
18:06:58.525 -> while
6
18:06:58.572 -> while
7
18:06:58.572 -> while
8
18:06:58.572 -> while
9
18:06:58.572 -> while
10
18:06:58.572 -> while
11
18:06:58.572 -> while
12
18:06:58.572 -> while
13
18:06:58.619 -> while
14
18:06:58.619 -> while
15
18:06:58.619 -> while
16
18:06:58.619 -> while
17
18:06:58.619 -> while
18
18:06:58.619 -> while
19
18:06:58.666 -> while
20
18:06:58.666 -> while
21
18:06:58.666 -> while
22
18:06:58.666 -> while
23
18:06:58.666 -> return B
24
18:06:58.666 -> polled
25
18:06:58.712 -> while
26
18:06:58.712 -> while
27
18:06:58.712 -> while
28
18:06:58.712 -> while
29
18:06:58.712 -> while
30
18:06:58.712 -> while
31
18:06:58.759 -> while
32
18:06:58.759 -> while
33
18:06:58.759 -> while
34
18:06:58.759 -> while
35
18:06:58.759 -> while
36
18:06:58.759 -> while
37
18:06:58.759 -> while
38
18:06:58.806 -> while
39
18:06:58.806 -> while
40
18:06:58.806 -> while
41
18:06:58.806 -> while
42
18:06:58.806 -> while
43
18:06:58.806 -> while
44
18:06:58.853 -> while
45
18:06:58.853 -> return B
46
18:06:58.853 -> polled
47
18:06:58.853 -> while
48
18:06:58.853 -> while
49
18:06:58.853 -> while
50
18:06:58.900 -> while
51
18:06:58.900 -> while
52
18:06:58.900 -> while
53
18:06:58.900 -> while
54
18:06:58.900 -> while
55
18:06:58.900 -> while
56
18:06:58.900 -> while
57
18:06:58.947 -> while
58
18:06:58.947 -> while
59
18:06:58.947 -> while
60
18:06:58.947 -> while
61
18:06:58.947 -> while
62
18:06:58.947 -> while
63
18:06:58.994 -> while
64
18:06:58.994 -> while
65
18:06:58.994 -> while
66
18:06:58.994 -> while
67
18:06:58.994 -> return B
: Bearbeitet durch User
Beitrag #8043545 wurde vom Autor gelöscht.
von Ralph S. (jjflash)


Lesenswert?

Veit D. schrieb:
> Mir wäre es jedoch wichtiger, wenn man über die vermeintliche
> Nichtblockierung nicht hinweg sehen würde. Deshalb nochmal der Hinweis,
> dass polled_delay() blockierend wirkt.

Natürlich ist das blockierend, sonst wäre es kein delay. Ich sagte, dass
es für die benötigten I/O Dinge ( ADC und Dip-Schalter ) nicht
blockierend ist. Der Wert des ADC manipuliert hier das Ende der
Wartezeit und eine Veränderung der Dip-Schalterstellung beendet die
Delay sofort, damit sich im "loop" darum gekümmert werden kann.

Normalerweise würde man einen Timerinterrupt mit einem ISR-Aufruf jede
Millisekunde initialisieren, einen Interrupt für den ADC, der eine 
Variable
ständig neu beschreibt ebenso. In der Timer ISR selbst wird dann nur 
noch da
Ende einer laufenden Sequenz berechnet und entsprechend eine globale
Variable gesetzt über die in der "loop" gepollt werden kann. Gleiches
gilt für den Dip-Schalter: Pinchange-Interrupt initialisieren und Flag
setzen.

Aber: Interrupts waren nicht erlaubt. Hier ist der Aufgabentext, 1:1 aus
der Aufgabenbeschreibung übernommen (aus meiner Sicht der Dinge hat sich
jemand bei dieser Beschreibung jemand nicht wirklich mühe gemacht.

Aufgabenbeschreibung:
---------------------------------------------------

Programmieren Sie ein Lauflicht mit 8 Leuchtdioden, dessen
Ablaufgeschwindigkeit über
ein Potenziometer einstellbar ist. Das Lauflicht soll insgesamt 4
Leuchtmuster beinhalten,
die über einen zweipoligen Mini-Dipschalter auswählbar sind.

Verwenden Sie bei der Programmierung KEINE Interrupts. Die Ansteuerung
der Leuchtdioden
erfolgt über ein Schieberegister SN74HC595. Verwenden Sie aus der
Library "sn74hc595"
nur den Konstruktor und bilden Sie ein Objekt aus der Klasse
"shiftreg595" ab.
Aus diesem erstellten Objekt ist die Methode "setvalue" zur Ansteuerung
der LEDs
zu verwenden. Die Dokumentation der Library finden Sie auf dem Server.

Versehen Sie Ihr Programm mit Kommentaren. Im Kopfkommentar ist
anzugeben:

- Sketchname "sr595_lauflicht.ino"
- Ihr Name
- Ihre Schulklassenbezeichnung
- Ihr Ausbildungsberuf
- Schularbeit: Lauflichtprojekt 1b
- Framework: Arduino

Gegeben ist:

- Arduino mit ATmega328p Prozessor
- Schieberegistermodul mit SN74HC595 und 8 Leuchtdioden
- 10 KOhm Potenziometer
- Library "sn74hc595"

Viel Erfolg und Spaß beim Tüfteln
von Veit D. (devil-elec)


Lesenswert?

Hallo,

ich möchte jetzt nicht über Aussagen streiten. Kann jeder nachlesen. Nur 
wie man die Blockierung weg bekommt hatte ich auch gesagt. Die Arduino 
IDE bringt dafür ein Bsp. mit - BlinkWithoutDelay. Man muss nur die 
vorhandene millis() Funktion richtig nutzen. Dann hat man zu keiner Zeit 
eine Blockierung - egal wofür. In der Hinsicht verstehe ich bis heute 
nicht, warum man dann immer wieder und wieder und wieder mit dem 
Scheinargument um die Ecke kommt
> Normalerweise würde man einen Timerinterrupt mit einem ISR-Aufruf
> jede Millisekunde initialisieren, ...
Weil das muss man nicht tun, wenn man millis() verwendet. Das ist dafür 
da.
Also entweder man verwendet Arduino und nimmt millis(). Oder man 
programmiert ohne Framework und programmiert seinen eigenen Timer. Weil 
Arduino verwenden und eigenen Timer für solche Zeitfunktionen/Vergleiche 
ist so richtig Sinnfrei. Aber dieses gegenseitige Ausspielen von 
Argumenten die in der Beziehung zueinander einfach nur sinnlos sind, 
dass stört mich maßlos. Das bringt auch diese Unterhaltung nicht weiter. 
Man tritt auf der Stelle. Man benötigt schlicht und ergreifend für diese 
Aufgabe keine eigene Interrupt Routine.
von Bruno V. (bruno_v)


Lesenswert?

Rolf schrieb:
> Du hast richtig gelesen? Für eine "richtigen" Programmierer ist es 4
> minus, für den Azubi aus einem anderen Fach nicht.

90% aller “richtigen“ Programmierer hätten es nicht besser gemacht. Sie 
halten sich höchstens an willkürlich von Dir favorisierte Paradigmen, 
wenn Du sie bewertest.
von Veit D. (devil-elec)


Lesenswert?

Bruno V. schrieb:

> Für die Nicht-Laboranten: Programmierung ist nur ein Teilbereich von
> ganz vielen anderen: Quasi so, wie SPS-Programmierung beim Schlosser
> oder CNC-Programmierung beim Schreiner.

Wenn dem so ist, dann sieht das gezeigte Programm gar nicht schlecht 
aus. Bewerten in Noten kann ich es dennoch nicht.

Abgesehen davon hätte die Schule die Aufgabe anders stellen können. 
Weniger Klimmbimm mit den Mustern. Dafür den 74HC595 zu Fuss 
angesprochen ohne fertige Lib. Das ist nämlich gar nicht so schwer. Dann 
hätte man gelernt bzw. abgefragt ob man das Datenblatt lesen und damit 
paar wenige benötigte Zeilen schreiben kann. Dann reicht es ein 
einfaches Lauflicht zu programmieren. Hätte mir besser gefallen. ;-)
von Ralph S. (jjflash)


Lesenswert?

Veit D. schrieb:
>> Normalerweise würde man einen Timerinterrupt mit einem ISR-Aufruf
>> jede Millisekunde initialisieren, ...
> Weil das muss man nicht tun, wenn man millis() verwendet. Das ist dafür
> da.
> Also entweder man verwendet Arduino und nimmt millis(). Oder man
> programmiert ohne Framework und programmiert seinen eigenen Timer.

ich hätte wohl dazuschreiben sollen, was für mich "normalerweise" ist. 
Wie du ganz richtig erkannt hast: Programmieren OHNE Arduino-Framework ! 
Meine Güte. Es ging hier darum, wie etwas zu bewerten ist.

Sagen wir es so: Wärst du Berufsschullehrer, würde ich nicht gerne dein 
Schüler sein wollen!

Aber: das ist deine Meinung und aus dieser Sache heraus erklärt sich 
vllt. auch die Note, die vergeben worden ist.

Ich bleibe auch dabei, dass das für den Lehrling eine gute bis sehr gute 
Arbeit war, schlicht weil er sich ein paar Gedanken mehr gemacht hat, 
als einfach nur Hexzahlen einzugeben und die nacheinander herunterlaufen 
zu lassen. Blockierend hin, blockierend her (mal so ganz davon 
abgesehen, dass das für dieses Programm so überhaupt keine Rolle 
spielt).
von Bri (bri)


Lesenswert?

Vom Schreibstil der Kommentare erinnert der Sourcecode schon etwas an 
das, was Claude Sonnet o.ä. ausgeben würde.

Wenn er es wirklich selbst programmiert hat, dann finde ich die 3,2 aber 
echt zu schlecht bewertet. Es ist strukturiert programmiert. Er nutzt 
Funktionen. Es ist gut kommentiert. Da sieht man von Schülern oft viel 
schlechteres.
Nützt aber leider nix, weil wenn der Lehrer das anders sieht, wird er 
sich wahrscheinlich nicht umstimmen lassen.

PS:
Weil hier ChatGPT in Zusammenhang mit programmieren erwähnt wurde. 
Probiert mal Claude Sonnet oder besser noch Claude Opus aus. Ist echt 
erstaunlich was diese KIs für Sourcecode erstellen können. Da frage ich 
mich, ob der Beruf des reinen Programmierers noch eine Zukunft hat.
von Bruno V. (bruno_v)


Lesenswert?

Veit D. schrieb:
> Abgesehen davon hätte die Schule die Aufgabe anders stellen können.
> Weniger Klimmbimm mit den Mustern. Dafür den 74HC595 zu Fuss
> angesprochen ohne fertige Lib. Das ist nämlich gar nicht so schwer. Dann
> hätte man gelernt bzw. abgefragt ob man das Datenblatt lesen und damit
> paar wenige benötigte Zeilen schreiben kann.

Wir reden hier nominell von einem 17jährigem, der nicht das Zeug zum 
Abitur hat.

Ich bitte doch mal alle Programmierer hier, das mit ihrem Code mit 17 zu 
vergleichen. Und zu bedenken, dass 80% in diesem Beruf niemals embedded 
programmieren.

Dass es auch Lehrlinge mit Abitur gibt, geschenkt.
: Bearbeitet durch User
von Alexander (alecxs)


Lesenswert?

Ralph S. schrieb:
> Bei einigen Teilen war ich dabei wie er das geschrieben hat. Wenn er
> hier KI (chatgpt ?) eingesetzt hat, dann aber garantiert nicht für
> dieses Programm.

Ich habe mir den Code nicht angesehen da ich den wohl sowieso nicht 
verstehen würde. KI für Hausaufgaben hatte ich in der heutigen Zeit als 
normal vorausgesetzt.

Aber stimmt, KI hätte nicht die Transliteration für Umlaute benutzt, und 
außerdem fehlen da jede Menge Emojis, Pfeile und Kästchen ;)
von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Alexander schrieb:
> Ich habe mir den Code nicht angesehen da ich den wohl sowieso nicht
> verstehen würde.

Aber ein Urteil raus posaunen.
Ohne Fundament.
von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Bri schrieb:
> Vom Schreibstil

Er entspricht, in großen Teilen, nicht den üblichen 
Konventionen/Vereinbarungen in der Arduino (oder auch C++) Welt.

Je nachdem was vorher in der Schule gelaufen ist, kann das den 
Punktabzug begründen.
von Alexander (alecxs)


Lesenswert?

Sind doch nicht meine Hausaufgaben. Das beurteilen überlasse ich lieber 
den Experten.
von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Alexander schrieb:
> Vielleicht weil die Urheberschaft der dafür genutzten KI nicht mit
> angegeben wurde?

Das ist ein Urteil!

In Form einer vernichtenden Behauptung, die sich offensichtlich als 
falsch herausgestellt hat.
von Alexander (alecxs)


Lesenswert?

Arduino F. schrieb:
> Das ist ein Urteil!

Nö! Das ist eine Anfrage, maximal eine Suggestion, auch Anregung 
genannt. Mit Urteilen sind hier andere gut dabei.
von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Alexander schrieb:
> Das ist eine Anfrage

Nein!
Eher eine rhetorische Frage.

Eine rhetorische Frage ist eine Scheinfrage, auf die keine Antwort 
erwartet wird, da die Antwort offensichtlich ist oder die Frage als 
nachdrückliche Aussage dient. Sie wird als stilistisches Mittel 
eingesetzt, um Aufmerksamkeit zu steigern, Meinungen zu verstärken oder 
das Gegenüber zu manipulieren/überzeugen.
von Veit D. (devil-elec)


Lesenswert?

Ralph S. schrieb:

eigentlich ging es mir nur darum der Aussage es wäre nicht blockierend 
zu widersprechen und nun sehen wir was aus dem Wortwechsel geworden ist.

> Sagen wir es so: Wärst du Berufsschullehrer, würde ich nicht gerne dein
> Schüler sein wollen!

Die Vorlage muss ich nutzen. ;-) Dann würdest du nicht lernen wie man 
millis() für alles mögliche verwenden kann, wie man damit nicht 
blockierend programmiert und wie man C und C++ Code Style nicht 
vermischt. :-)

Wegen der Benotung nochmal. Man müsste wissen was in der Schule 
behandelt wurde. Das ist ja ganz sicher keine fakultative Aufgabe 
gewesen. Es reicht schon aus, wenn der Berufsschullehrer und du einen 
anderen Code Style an den Tag legt. Schon hat der Azubi, der zwischen 
den Stühlen steht, schlechte Karten usw. Auch ist die Priorität der 
Aufgabe nicht bekannt. Muss es nur funktionieren. Muss der Code gut 
aussehen. usw.

Ich will jetzt nicht weiter darauf rumhacken.
Ich wünsche dir Ralph dennoch bei allen Wortwechseln hier und da paar 
ruhige Tage. Alles gut.
von J. T. (chaoskind)


Lesenswert?

Arduino F. schrieb:
> Aber ein Urteil raus posaunen.
> Ohne Fundament.

Das ist doch uns Alex ihm seine Kernkompetenz :D
Beitrag #8043862 wurde von einem Moderator gelöscht.
von Ralph S. (jjflash)


Lesenswert?

Veit D. schrieb:
> Die Vorlage muss ich nutzen. ;-) Dann würdest du nicht lernen wie man
> millis() für alles mögliche verwenden kann, wie man damit nicht
> blockierend programmiert und wie man C und C++ Code Style nicht
> vermischt. :-)

Die Arroganz und die Überheblichkeit auf mikrocontroller.net kennt keine 
Grenzen und der Wettbewerbssiege in dieser Dispziplin ist, "the winner" 
is (darf man Englisch und Deutsch miteinander vermischen?!?): Tatäääää 
(suche es Dir raus).

Nur um es zu verdeutlichen: Das Lauflichtprogramm ist nicht von mir. Ich 
verwende im Normalfall auch keine millis, weil ich im Normalfall auch 
kein Arduino verwende. Aber ich habe in Arduino etwas hereingesehen, so 
wie du das in einem anderen Thread bereits kommentiert hast. Bisweilen 
sollte man manchmal manche Menschen an der Nase packen und sagen, dass 
vieles nicht zwingend in einem akademischen Stil gemacht werden muß und 
das gilt insbesondere im Embeddedbereich.

Also, ich weiß wie man NICHT blockierend programmiert, ich kann (und das 
schon lange, allerdings nicht in Arduino) mittels Interrupts GPIOs, ADC, 
UART oder auch anderes lesen und einen Ringpuffer befüllen der 
ausgewertet wird. Stell dir vor ich kann sogar DMA auf unterschiedlichen 
Controllern (sorry an alle anderen dass ich das jetzt "raushängen 
lasse"). Diese Frechheit von "sugestiven" Äußerungen die jemand anderen 
dumm dastehen lassen ist bald nicht zum Aushalten.

By the way: Ich habe hier noch kein Projekt, noch keine Arbeit, kein 
nichts gesehen, jedoch grundsätzliche Nörgelei en Masse. Wenn etwas 
größer wird, gibt es auch immer mehr Dinge daran zu kritisieren, was 
normal ist. Menschen wie du jedoch werden persönlich und das ist absolut 
daneben.

So, weil ich von dir lernen könnte (was ich extrem stark bezweifle, denn 
von Menschen, die stur an Paradigmen festhalten und nicht wissen, wann 
es sinnvoll ist, davon abzuweichen, kann ich nichts lernen).

Zu deiner "genialen" Darstellung von blockierend hast du das hier 
gemacht:
1
uint8_t polled_delay(uint8_t dipkey_status)
2
3
{
4
  Serial.println("polled");
5
6
  uint32_t start = millis();
7
  uint32_t runtime;
8
  uint8_t dipkeys;
9
10
  while (1)
11
  {
12
    dipkeys = dipkey_get();         
13
    if (dipkeys != dipkey_status)
14
    {
15
      Serial.println("return A");
16
      return dipkeys;
17
    }
18
19
    runtime = millis() - start;       
20
    if (runtime >= runspeed_get())
21
    {
22
      Serial.println("return B");
23
      return 0x80;                   
24
    }
25
    Serial.println("while");
26
  }
27
}

gibt es eine nette Aussage meines Lehrlings: "Wenn er doch dort, wo er 
Serial.println("while") schreibt, die Funktionen einhängt, die während 
der Wartezeit bearbeitet werden sollen, dann blockieren die doch dort 
nicht. Er hatte da ja sogar genug Zeit, wiederholt println aufzurufen".

Ich sage dir was: Er hat im Prinzip schlicht recht. An genau dieser 
Stelle blockiert nichts. Jetzt kann man sich über die Paradigmen von 
Arduino streiten oder nicht, manchmal kann man Werkzeuge (und Arduino 
ist ein Werkzeug) auch anderst benutzen als es ursprünglich gedacht war. 
Ich muß zugeben, "Asche auf mein Haupt", je mehr ich mich damit 
beschäftige, verändert sich meine Meinung darüber und verstehe, warum 
das für einige eine gute Lösung und sogar mehr als ein Einstieg in die 
Embedded-Welt sein kann).

Immerhin: :-) ich weiß schon, warum ich mit dir nicht mehr "diskutieren" 
wollte. Götter machen Regeln, sie diskutieren nicht. Schade nur, dass 
ich an Götter nicht glaube!
von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Ralph S. schrieb:
> An genau dieser
> Stelle blockiert nichts.

Ich stimme nicht zu!

Ich sage:
Man braucht nur eine while(1) bzw. Endlosschleife in einem Programm.
Und die steckt bei Arduino unzugänglich in main()
Bei Nutzung eines Multitaskingsystems wird das anders aussehen.
Beitrag #8043893 wurde vom Autor gelöscht.
von Veit D. (devil-elec)


Lesenswert?

Hallo Ralph,

ich belasse das unkommentiert. Es ist mir egal was du von mir denkst.
Die Standpunkte können klarer nicht sein.
Und wegen Code zeigen o.ä..
Habe ich hier hin und wieder getan, bin aber meistens im Arduino Forum 
unterwegs. Dort wird meine Hilfe dankend angenommen.
: Bearbeitet durch User
Beitrag #8043981 wurde von einem Moderator gelöscht.
von Re D. (re_d272)


Lesenswert?

Ralph S. schrieb:
> Grundsätzlich hat er etwas gemacht, von dem er wahrscheinlich die
> Fachbegriffe gar nicht kennt.

Gott bist du naiv. Die KI hat das gemacht. Wach auf.
von 900ss (900ss)


Angehängte Dateien:

Lesenswert?

Re D. schrieb:
> Die KI hat das gemacht

Sehe ich nicht so, evtl. hat er sich per KI Informationen besorgt. Was 
aber spricht dagegen in der heutigen Zeit wo KI ein Werkzeug ist?

Und damit man sehen kann wie KI erzeugter Code zu der Aufgabe aussieht, 
habe ich diese in 3 unterschiedliche KI gesteckt und die jeweiligen 
Ergebnisse hier angehängt.

Ich habe keine Datei verändert.

Eine Ähnlichkeit mit dem Code des Azubis ist nicht zu erkennen. Und mir 
sieht sein Code auch nicht nach KI aus.
von 900ss (900ss)


Lesenswert?

Es wird einmal sogar einmal der Wunsch nach nicht blockierendem "Warten" 
bedient.

Ich sehe das in dieser Aufgabe aber als völlig unerheblich an.

Die Aufgabe ist klar gestellt und für diese ist die Lösung des Azubis 
völlig ausreichend.

Er hat es sogar so implementiert, dass das "Nutzerinterface" garnicht 
verzögert reagiert. Also der Delay ist nicht zu merken. Er hat sich 
darüber also Gedanken gemacht und das entsprechend gelöst. Ich finde 
immer noch dass er die Ausgabe gut gelöst hat.

2 der KIs haben das nicht geschafft.

Klar findet man Stellen die man "verbessern" kann. Aber einiges sind 
auch eher persönliche Vorlieben.
Man darf auch nicht vergessen dass es ein völliger Anfänger ist.
: Bearbeitet durch User
von Ralph S. (jjflash)


Lesenswert?

900ss schrieb:
> Er hat es sogar so implementiert, dass das "Nutzerinterface" garnicht
> verzögert reagiert. Also der Delay ist nicht zu merken. Er hat sich
> darüber also Gedanken gemacht und das entsprechend gelöst. Ich finde
> immer noch dass er die Ausgabe gut gelöst hat.

Volle Zustimmung...

900ss schrieb:
> Klar findet man stellen die man "verbessern" kann. Aber einiges sind
> auch eher persönliche Vorlieben.

Auch hier: volle Zustimmung. Hier muß ich zugeben, dass ich ihm im 
Grunde meinen "Stil" aufzwinge. Weiß ich nicht ob das gut oder schlecht 
ist. Aber zumindest im Sinne der Kommentare möchte ich das so haben.

Zudem muß ich sagen, dass im Zuge der Ausbildung nur der Schule wegen 
Arduino benutzt wird, ansonsten ist bei Unterweisungen C angesagt (was 
viele Aussagen der Vorredner erklären dürfte)
von 900ss (900ss)


Lesenswert?

Ralph S. schrieb:
> Weiß ich nicht ob das gut oder schlecht ist.

Nörgler (oder Neider ;) ) findet man immer!

Das ist zu 50% persönliche Vorliebe.
von Chris V. (nagut)


Lesenswert?

Veit D. schrieb:
> den 74HC595 zu Fuss
> angesprochen ohne fertige Lib. Das ist nämlich gar nicht so schwer. Dann
> hätte man gelernt bzw. abgefragt ob man das Datenblatt lesen und damit
> paar wenige benötigte Zeilen schreiben kann. Dann reicht es ein
> einfaches Lauflicht zu programmieren.

Ich hatte auch damit gerechnet, dass es dem Lehrer um das direkte 
ansprechen des Schieberegisters gegangen sein könnte, und die Verwendung 
der Library dann zur Abwertung geführt hat. Nachdem jetzt aber der 
originale Aufgabentext gezeigt wurde, und da sogar explizit drin steht, 
dass man die Library benutzen soll, fällt das auch flach.

Mein Fazit: Die Lösung ist deutlich besser als 3,2.

Leider ist es in vielen Schulen so, dass die Aufgabenstellung nicht 
alles enthält. Man muss seine Lehrer und deren Vorlieben kennen, und 
(leider) immer auch interpretieren, was sie mit bestimmten 
Formulierungen oder auch generell wohl meinen und erwarten. Es ist 
schade, dass die Abwertung hier offenbar jemanden trifft, der sich 
eigene und gute Gedanken zum Problem gemacht hat.

Ob man sich hier als Ausbilder einschalten sollte, ist allerdings nicht 
unbedingt klar. Ich denke ich würde dem Azubi meine Wertschätzung für 
seine Leistung deutlich machen, und ihm klar sagen, dass für mich nicht 
ersichtlich ist, warum die Note nicht besser ausgefallen ist. Je nach 
Mentalität von sowohl Azubi als auch Berufsschullehrer (und vielleicht 
auch dem Klassenzusammenhalt - Stichwort Mobbing von vermeintlichen 
"Strebern") könnte sich der Azubi dazu entschließen, selbst beim 
Berufsschullehrer nachzufragen.
von Veit D. (devil-elec)


Lesenswert?

Hallo

Ich fasse das einmal zusammen.
Es wird leider bis jetzt nicht verstanden, dass die polled_delay() mit 
ihrer while(1) zur neuen Hauptschleife geworden ist. Alles was in loop() 
steht wird davon blockiert. Man muss alles in die neue Ersatz - while(1) 
schreiben damit nichts blockiert. Offensichtlich wurde hier etwas nicht 
verstanden. Nun gibt Ralph offen zu, dass der Azubi seinen 
Programmierstil übernommen hat und fragt sich gleichzeitig ob das gut 
oder schlecht ist. Wenn ich um die Ecke komme und den negativen Teil 
bestätige, gibt's Streit. Will man nicht hören. Würde hier im Forum 
jemand eine Hauptfunktion polled_delay() benennen? Mit versteckten 
while(1)? Ich denke nicht. Warum redet man das schön?

Wenn der Azubi und Ralph verstehen wollen, warum es nur eine 3,2 gab, 
dann hätte man den Berufsschullehrer schon längst danach gefragt, 
welches Ziel er hatte und was er bemängelt. Oder wie seine Musterlösung 
aussieht. Dann hätte man konkret darüber reden können.

> Zudem muß ich sagen, dass im Zuge der Ausbildung nur der Schule wegen
> Arduino benutzt wird, ansonsten ist bei Unterweisungen C angesagt (was
> viele Aussagen der Vorredner erklären dürfte)

Eine Salamischeibe. Das bestätigt meine Einschätzung und zeigt das 
Problem. Es gab keine Absprache wie man den Stoff "Programmierung" 
gemeinsam vermittelt. Der Azubi ist der Leid tragende und steht zwischen 
Stühlen.

Ich hatte ja schon geschrieben, wenn es nur um die reine Funktion geht, 
dann ist es okay. Geht es dem Berufsschullehrer um andere Aspekte, die 
wir eben nicht kennen, dann ist der Raum für alle Kritik offen. Leider 
geht es hier nur darum, dass man eine Einschätzung bestätigen soll und 
keine Kritik zulässt. Widerspricht man der Einschätzung knallt es. Dann 
sollte man jedoch keinen Thread dazu eröffnen.

Wünsche dennoch allen einen ruhigen Feiertag.
von 900ss (900ss)


Lesenswert?

Veit D. schrieb:
> Widerspricht man der Einschätzung knallt es.

Bei mir knallt nichts. Ich sehe die Notwendigkeit eines "nicht 
blockerens" hier eher nicht als gegeben an.

Wenn man vermitteln möchte, wie man es machen kann, damit loop() nicht 
blockiert, dann ist dein Vorschlag gut.

Aber ist in der Aufgabe meines Erachtens nicht gefragt und auch nicht 
notwendig.

Und der Azubi hat sich Gedanken gemacht, wie er es löst, damit das "UI" 
nicht hängen bleibt und hat es gut gelöst.

Ich sehe nur einen der hier mit den Füßen trampelt ;)
von Alexander (alecxs)


Lesenswert?

Veit D. schrieb:
> Alles was in loop() steht wird davon blockiert.

Aber genau das ist doch der Zweck der Funktion. Darf man Dich so 
interpretieren dass Du grundsätzlich jedes delay() in der loop() 
kritisierst?
von Bruno V. (bruno_v)


Lesenswert?

Wenn mich etwas triggert, dann ist es while(1).

Ich habe zu wenig Ahnung von C++ oder Arduino. Und für alle hier scheint 
das normal. In C würde das bei uns nicht durchgehen, wegen der 
Warnungen. Es gibt dafür ja extra ein eigenes Konstrukt.
von Alexander (alecxs)


Lesenswert?

schlimmer finde ich `for (;;)`
von Veit D. (devil-elec)


Lesenswert?

900ss schrieb:

> Ich sehe nur einen der hier mit den Füßen trampelt ;)

Ich nehme an du meinst mich und nicht Ralph. ;-) Eine eher einseitige 
Betrachtung, weil ich konkrete Dinge angesprochen habe, die zur 
Verbesserung des Programm dienen sollen. Wenn das nicht gehört werden 
möchte, soll es mir nun auch langsam egal sein. Was ich nicht leiden 
kann, ist dieses schön reden, wenn man doch Probleme sieht und diese 
anspricht. Mir ist Klartext um Welten lieber.

Alexander schrieb:
> Veit D. schrieb:
>> Alles was in loop() steht wird davon blockiert.
> Aber genau das ist doch der Zweck der Funktion.
Das ist jedoch im Zusammenhang mit der ohnehin vorhandenen loop() 
doppelt gemoppelt und Irreführend. loop() dient nicht dazu von irgendwas 
blockiert zu werden. Alles andere hatte ich geschrieben.

> Darf man Dich so interpretieren dass Du grundsätzlich jedes delay()
> in der loop() kritisierst?
Ja darf man. Über 1ms hartes delay kann man mit mir noch reden. :-) Aber 
wie hier 40 bis 381ms würde ich nicht zulassen. Zudem ja hier millis() 
verwendet wird und dennoch die loop() blockierend programmiert wurde. 
Stell dir einmal vor du müsstest das Programm erweitern und erwartest 
kurze Reaktionszeiten. Du hast mit der loop() keine Chance. Du wärest 
gezwungen alles in die while(1) zu schieben bzw. darin aufrufen zu 
lassen. Ich weiß das es hier keine Rolle spielt, so wie das Programm 
geschrieben ist. Nur sollte ich unschöne Dinge dennoch ansprechen können 
dürfen. Das wird mir jedoch mit Argumenten die nichts mit Programmierung 
zu tun haben praktisch untersagt bzw. will man das nicht hören. Das kann 
es nun auch nicht sein.
von Veit D. (devil-elec)


Lesenswert?

Bruno V. schrieb:
> Wenn mich etwas triggert, dann ist es while(1).
>
> Ich habe zu wenig Ahnung von C++ oder Arduino. Und für alle hier scheint
> das normal. In C würde das bei uns nicht durchgehen, wegen der
> Warnungen. Es gibt dafür ja extra ein eigenes Konstrukt.

Da kann ich aushelfen.
Klassisch C oder C++
1
int main() {
2
  // einmaliger Initialisierungscode
3
  // ...
4
  while(1) {
5
    // sinnvoller Programmcode in der Hauptschleife  
6
    // ...  
7
  }
8
}

mit Arduino Framework
1
void setup() {
2
  // einmaliger Initialisierungscode
3
  // ...
4
}
5
6
void loop() {
7
  // sinnvoller Programmcode in der Hauptschleife 
8
  // ...   
9
}
von Nemopuk (nemopuk)


Lesenswert?

Bruno V. schrieb:
> Wenn mich etwas triggert, dann ist es while(1).

Alexander schrieb:
> schlimmer finde ich `for (;;)`

In irgendeinen Framework bin ich mal auch ein "forever" Makro gestoßen. 
Habe aber keine Anwendung davon zu Gesicht bekommen, nur die Definition.
: Bearbeitet durch User
von Alexander (alecxs)


Lesenswert?

Gut dass wir hier vom selben reden. Dann habe ich auch mal etwas 
verstanden. Wenn man mehrere Sachen hat muss man sich natürlich Gedanken 
machen. Auf dem ESP32 kann man auch Sachen auf mehrere Tasks aufteilen. 
Da ist die loop() ein Task wie jeder andere für mich, eine der Sachen 
darf ruhig die loop() für sich alleine haben. Für den Arduino bleibt 
dann wohl nur die millis() zu pollen, wenn die sich die loop() teilen 
müssen.
von 900ss (900ss)


Lesenswert?

Veit D. schrieb:
> Stell dir einmal vor du müsstest das Programm erweitern und erwartest
> kurze Reaktionszeiten. Du hast mit der loop() keine Chance. Du wärest
> gezwungen alles in die while(1) zu schieben bzw. darin aufrufen zu
> lassen.

Ja, wenn man das Programm so erweitern müsste wäre das in der Tat 
schwierig. Aber diese Aufgabe war klar umrissen und Erweiterbarkeit war 
nicht gefordert.

Insofern hat der Azubi alles richtig gemacht. Sogar erkennbar mit 
Nachdenken.

Die Kritik mit dem Blockieren ist richtig wenn es hier ein Problem wäre. 
Es ist allerdings ein hypothetisches Problem. Insofern weiß ich nicht 
weshalb sich so dagegen gewehrt wird, dass die Aufgabe hinreichend gut 
gelöst wurde.

Man könnte dem Azubi jetzt die Aufgabe geben, in loop() eine LED mit 
konstanter Zykluszeit blinken zu lassen. Dann würde er das vermutlich 
erkennen was anders sein muss und das umsetzen. Zur Übung sicher ganz 
gut für ihn.

So, jetzt weiter Trampeln ;)
von Veit D. (devil-elec)


Lesenswert?

Hallo,

mein Beitrag zur Güte. Man kann Tausende Instanzen erstellen und nichts 
davon kommt sich in die Quere.
1
/*
2
  devil-elec - https://www.mikrocontroller.net/
3
  IDE 1.8.19
4
  avr-gcc: 7.5.0
5
  Arduino Mega 2560
6
  01.05.2026
7
*/
8
9
class SimpleTimer
10
{
11
  private:
12
    const bool mode; // 'true' konstant, driftet nicht weg, 'false' holt Fehlzeit nicht auf
13
    bool isRunning       {false};
14
    unsigned long lastMillis {0};
15
    unsigned long duration   {0}; 
16
17
  public: 
18
    SimpleTimer (unsigned long d, bool m = false): 
19
      duration {d}, 
20
      mode {m}
21
    {}   
22
23
    /***********************************************************************************************
24
    Function: void start (void)
25
    Purpose:  startet den Timer, ohne Retrigger
26
    Input:    none
27
    Returns:  none         
28
    ************************************************************************************************/
29
    void start (void) {
30
      if (0 < duration) { 
31
        lastMillis = millis();
32
        isRunning = true; 
33
      }  
34
    }
35
36
    /***********************************************************************************************
37
    Function: void stop (void)
38
    Purpose:  stoppt den Timer, ohne Retrigger
39
    Input:    none
40
    Returns:  none         
41
    ************************************************************************************************/
42
    void stop (void) { isRunning = false; }
43
    
44
    /***********************************************************************************************
45
    Function: void setTime (const unsigned long t)
46
    Purpose:  Stellt den Timer auf die gewünschte Laufzeit ein. Timer läuft immer neu an.
47
    Input:    Zeitspanne die der Timer laufen soll.
48
              Wenn '0' übergeben wird läuft der Timer nicht.
49
    Returns:  none          
50
    ************************************************************************************************/
51
    void setTime (const unsigned long t) { duration = t; }
52
    
53
    /***********************************************************************************************
54
    Function: unsigned long getDuration (void)
55
    Purpose:  gibt die aktuell eingestellte Zeit zurück
56
    Input:    none
57
    Returns:  unsigned long duration          
58
    ************************************************************************************************/ 
59
    unsigned long getDuration (void) const { return duration; } 
60
    
61
    /***********************************************************************************************
62
    Function: bool expired (void) 
63
    Purpose:  gibt zum Zeitpunkt der Abfrage einmalig 'true' zurück, wenn die Zeitdifferenz erreicht wurde.
64
              Wurde der Timer gestoppt, gibt es kein 'true' zurück.
65
    Input:    none
66
    Returns:  ein bool Trigger (ist nicht statisch)       
67
    ************************************************************************************************/
68
    bool expired (void) { 
69
      bool state {false};  
70
      const unsigned long millisNow { millis() };
71
      if (isRunning && (millisNow - lastMillis >= duration)) {
72
        if (mode) { lastMillis += duration;  } // konstantes Intervall, driftet nicht weg, holt auf
73
        else      { lastMillis  = millisNow; } // holt Fehlzeit nicht auf, driftet weg
74
        state = true;     
75
      }
76
      return state;
77
    }
78
};
79
80
SimpleTimer timerA {2000}; 
81
SimpleTimer timerB {4000};
82
83
void setup (void)
84
{
85
  Serial.begin(9600);
86
  Serial.println("\nuC Reset ###\n");
87
  timerA.start();
88
  timerB.start();
89
}
90
91
void loop (void)
92
{
93
  if (timerA.expired()) {
94
    Serial.println("A");
95
  }
96
97
  if (timerB.expired()) {
98
    Serial.println("B");
99
  }
100
}
von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Alexander schrieb:
> for (;;)
Üblich und völlig OK

Veit D. schrieb:
> while(1)
Üblich und völlig OK
1
constexpr bool stromAusfall  {false};
2
while(not stromAusfall)
3
{
4
// tuwas
5
}
von Veit D. (devil-elec)


Lesenswert?

Arduino F. schrieb:
> Veit D. schrieb:
>> while(1)
> Üblich und völlig OK

Jedoch nicht als verkorkster verschachtelter Ersatz für loop(), wenn 
loop() ohnehin verwendet wird.
: Bearbeitet durch User
von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Veit D. schrieb:
> Arduino F. schrieb:
>> Veit D. schrieb:
>>> while(1)
>> Üblich und völlig OK
>
> Jedoch nicht als verkorkster verschachtelter Ersatz für loop(), wenn
> loop() ohnehin verwendet wird.

Ja, nee....

Es drehte sich mir um die Glaubensfrage, welche der Endlosschleifen 
jetzt besser oder schöner ist.

Und ich sage: Egal!
Der Compiler macht in allen 3 Fällen das gleiche draus.
von Norbert (der_norbert)


Lesenswert?

Wenn es hier schon die ganze Zeit um Stil, Schönheit, Klarheit und 
Lesbarkeit geht, stellt sich mir eine Frage.

Wieso heißt die Funktion bei Arduino eigentlich ›loop()‹, obwohl sie 
genau das eben nicht macht?

Sie wird aufgerufen und beendet. Und zwar wiederholt und unregelmäßig, 
zudem auch noch in noch nicht einmal festen Zeitrastern.

Da hätte sie also schon von Anfang an einen vernünftigen und passenden 
Namen verdient.
›occasionally()‹, ›every_once_in_a_while()‹, …

›thanks_for_calling()‹  wäre ja mein persönlicher Favorit. ;-)
: Bearbeitet durch User
von Veit D. (devil-elec)


Lesenswert?

Arduino F. schrieb:
> Ja, nee....

0kay, ein Missverständnis. Aus dieser Glaubensfrage halte ich mich raus.
von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Norbert schrieb:
> Wieso heißt die Funktion bei Arduino eigentlich ›loop()‹
Wurde geerbt wie vieles andere auch.
Und modifiziert

Vorbild:
https://processing.org/reference
von Veit D. (devil-elec)


Lesenswert?

Norbert schrieb:

Wenn du nachgeschaut hast, müsstest du gesehen haben, dass zusätzlich 
ein Serial Eventhandler aufgerufen wird. Warum du loop() in einem 
zusätzlich bremsenden Zeitraster haben möchtest weiß ich nicht.
Es wird unmittelbar so schnell und so oft wie möglich aufgerufen.

> ›occasionally()‹, ›every_once_in_a_while()‹, …
>
> ›thanks_for_calling()‹  wäre ja mein persönlicher Favorit. ;-)

Stell ein Request.
von Norbert (der_norbert)


Lesenswert?

Veit D. schrieb:
> Norbert schrieb:
>
> Wenn du nachgeschaut hast, müsstest du gesehen haben, dass zusätzlich
> ein Serial Eventhandler aufgerufen wird. Warum du loop() in einem
> zusätzlich bremsenden Zeitraster haben möchtest weiß ich nicht.
> Es wird unmittelbar so schnell und so oft wie möglich aufgerufen.
>
>> ›occasionally()‹, ›every_once_in_a_while()‹, …
>>
>> ›thanks_for_calling()‹  wäre ja mein persönlicher Favorit. ;-)
>
> Stell ein Request.

1. Du zitierst falsch. Sehr falsch sogar.
2. Was intern passiert, hat mit der Frage nach dem irreführenden Namen 
nichts zu tun.
3. Ich will kein Zeitraster. Ich weiß noch nicht einmal wo du das 
gelesen haben willst.
4. Ich benutze das Zeug nicht. Dennoch muss eine solche Frage legitim 
sein.
5. Nicht gleich auf den Schlips getreten fühlen.
von Veit D. (devil-elec)


Lesenswert?

Lies bitte deinen eigenen Text von 16:35 Uhr.
von Norbert (der_norbert)


Lesenswert?

Veit D. schrieb:
> Lies bitte deinen eigenen Text von 16:35 Uhr.

Ich kenne den. Habe ihn selbst geschrieben.
Aber du möchtest mir bestimmt die Stelle zeigen, an der ich angeblich

>> Warum du loop() in einem
>> zusätzlich bremsenden Zeitraster haben möchtest weiß ich nicht.

gefordert haben soll. Das wird spannend.
: Bearbeitet durch User
von Veit D. (devil-elec)


Lesenswert?

Norbert schrieb:
> Veit D. schrieb:
>> Lies bitte deinen eigenen Text von 16:35 Uhr.
>
> Ich kenne den. Habe ihn selbst geschrieben.
> Aber du möchtest mir bestimmt die Stelle zeigen, an der ich angeblich
>
>>> Warum du loop() in einem
>>> zusätzlich bremsenden Zeitraster haben möchtest weiß ich nicht.
>
> gefordert haben soll. Das wird spannend.

Nichts leichter als das.

> Sie wird aufgerufen und beendet. Und zwar wiederholt und unregelmäßig,
> zudem auch noch in noch nicht einmal festen Zeitrastern.

Du wunderst dich über fehlende feste Zeitraster. Demzufolge wünscht du 
dir diese indirekt mit dieser Aussage. Warum muss ich fremder Leute 
Texte erklären?
von Norbert (der_norbert)


Lesenswert?

Veit D. schrieb:
> Du wunderst dich über fehlende feste Zeitraster. Demzufolge wünscht du
> dir diese indirekt mit dieser Aussage. Warum muss ich fremder Leute
> Texte erklären?

Ich wundere mich nicht, ich liste eine Reihe von Fakten auf.
Und nirgendwo steht, dass ich mir irgend etwas wünsche.
Das findet nur in deinem Kopf statt.

Wenn ich deine Replik lese, bei einer KI würde man jetzt von 
Halluzination sprechen.

Und zu guter Letzt, nein, du musst Texte nicht erklären. Das setzt 
nämlich vorhergehendes Verständnis voraus, was klar nicht gegeben ist.
von Veit D. (devil-elec)


Lesenswert?

Damit ist alles gesagt.
von 900ss (900ss)


Lesenswert?

Veit D. schrieb:
> mein Beitrag zur Güte

Der ist gut.... "zur Güte".... ;)
von Veit D. (devil-elec)


Lesenswert?

900ss schrieb:
> Veit D. schrieb:
>> mein Beitrag zur Güte
>
> Der ist gut.... "zur Güte".... ;)

Ich wusste das sowas positiv aufgenommen wird.
Meinen Humor lasse ich mir nicht nehmen.
von Ralph S. (jjflash)


Angehängte Dateien:

Lesenswert?

So, :-) zu "Meiner Güte" und für mich hier jetzt abschließend (weil mir 
manche Dinge eben wirklich keine Ruhe lassen und ich wie so oft von 
geneigten Forenmitglieder so dargestellt werde, als ob ich der Stümper, 
Nichtskönner und blabla bin, nur weil ich anderer Ansicht bin) hier 
meine Version eines Lauflichts, das - zumindest aus meiner Sicht - 
nichtblockierend ist.

Für das Programm hier habe ich sogar Teile des Lehrlingprogramms 
genommen und weiter "entwickelt".

Grundsätzlich ist das Programm hier etwas, das ich interruptbasierend 
auf einem STM32F030 und einem STM32F411 am Laufen hatte / habe, dort 
jedoch im Gegensatz zu hier in "Plain-C" und mit Interrupts.

Also habe ich mir einmal die Mühe gemacht, und mein eventbasierendes 
Rumpfprogramm nach Arduino portiert. Hier - so glaube ich - habe ich 
dann für Arduino dann glaube ich doch etwas gelernt (ohne Kommentar von 
mir ob mir das gefällt oder nicht), wie in Arduino etwas gerne 
gehandhabt werden sollte. Hier dann einen Dank an Arduino F. auch für 
Anmerkungen in einem anderen Thread (und garantiert keinen Dank an 
Nörgler, Besserwisser und Paradigmenfesthalter).

Ich habe das, auch wenn es immer noch "nur" ein Wrapper ist, so gut ich 
das konnte an Arduino angepasst und heraus gekommen ist mein 
"Eventbasierendes System unter bewußter Nichtnutzung von Interrupts).

Kern des Programms sind 2 Funktionen:

- event_scan
- event_handler

event_scan erfasst, wenn auch nur durch den Handler zyklisch gepollt, 
eventuell auftretende Events (bspw. das Ablaufen eines Timers, geänderte 
Schaltereinstellung oder das Eintreffen eines Zeichens auf der seriellen 
Schnittstelle).

event_handler wird durch die loop permanent aufgerufen und pollt dadurch 
permanent die "Events".

Als "Streitpunkt" stellte sich hier ja heraus, wie das zu realiseren sei 
(und das das von meinem Auszubildenden wohl nicht gut gemacht gewesen 
sei - was ich anderst sehe) und es natürlich nur über millis() gehen 
kann. Also habe ich (und nein, ich habe nicht von Veit abgeguckt) so 
etwas wie Softtimerfunktionen realisiert, einmal einen der mittels ADC 
seine Intervallzeit einstellen kann und einmal einen, der einfach nur 
per Vorgabewert seine Zeit einstellt.

Und - wie Veit das in seinem Programmschnippsel gezeigt hat - können von 
diesen class beliebig Objekte instanziert werden.

Um im Ganzen zeigen zu können, dass das hier nicht blockiert, habe ich 
dem Programm auch noch mittels Serial.available ein Event hinzugefügt, 
mit dem ausgewertet werden kann, ob es eine Aktivität auf der seriellen 
Schnittstelle gegeben hat. In diesem Falle erfolgt dann ein Speichern in 
einem Bufferstring durch anhängen des  eingehenden Zeichens an den 
Bufferstring. Sehr deutlich ist hier zu sehen, dass, obwohl auf der 
seriellen Schnittstelle ein String eingegeben werden kann, dennoch das 
Lauf- und das Blinklicht schön weiter vor sich hin werkeln.

Als kleine Besonderheit kann bei der Eingabe eines Strings über ein 
Terminal (hier meine ich nicht das wirklich unsägliche Terminal von 
Arduino, sondern ein "besseres" wie bspw. puTTY oder picocom oder 
ähnliches) das letzte eingegeben Zeichen gelöscht werden (über das - so 
denke ich - allseits bekannte "\b \b").

Zuvor schon hatte ich die sn74hc595 Library nach der 
Funktionsbeschreibung der Schule nachprogrammiert gehabt, die ich hier 
auch mit einstelle, damit das auch alles schön nachvollziehbar und 
compilierbar ist.

-------------------------------------------------

Grundsätzlich jedoch (und Arduino F.) möge es mir verzeihen, stellt sich 
mir die Frage, wieviele typische Arduino-Nutzer diesen Code hier 
verstehen und wieviele Anfänger diesen Code hier verstehen. Von daher 
ist eine Frage nach der Sinnhaftigkeit meines Codes schon berechtigt.

So, ich hoffe, dass damit die Diskussion ein Ende hat und noch einmal 
ein Danke an Arduino F., der unaufgeregt erzählt hat, wie Arduino-User 
etwas sehen und was sie wohl von Code erwarten.

Viele Grüße und gute Nacht, Ralph

PS: Ein Lehrer würde mir für meine Lauflichtversion wohl eine 4,0 als 
Schulnote geben, weil am Thema vorbei: Über 540 Zeilen Code nur für ein 
Lauflicht ist sogar aus meiner Sicht der Dinge etwas "zu arg".
von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Mal abgesehen von dem Stil, der nicht Ardoinotypisch ist, habe ich 2 
massive Fehler gefunden.

> if (millis() > (starttime + getadcmillis()))
> if (millis() > (starttime + overflow))

Beide if Statements fallen nach 49,x Tagen auf die Fresse!

millis() läuft irgendwann über.
kurz vorher läuft deine Addition über
Also ein Doppelüberlauf ohne Kompensation.

Dabei ist es doch so einfach, es richtig zu machen.
if (millis() - starttime > getadcmillis())
: Bearbeitet durch User
von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Auch steckt in deiner class shiftreg595 (min) eine seltsame Sache:
> inline void datHigh() { digitalWrite(dat, HIGH); }
Wenn Methoden innerhalb einer Klasse in einer *.h definiert sind, sind 
sie per default schon inline.
Das inline ist damit redundant bzw. flüssiger als Wasser.

Bei mir würde es eher so aussehen:
1
// #include "sn74hc595.h" // habe ich nicht
2
3
// shiftreg595  sr(7, 5, 6);
4
5
// class shiftreg595;
6
class ShiftReg595
7
{
8
  private:
9
    const uint8_t clk;
10
    const uint8_t dat;
11
    const uint8_t stb;
12
13
  public:
14
    ShiftReg595(uint8_t clk, uint8_t dat, uint8_t stb)
15
      : clk(clk), dat(dat), stb(stb) {}
16
17
    void setValue(const uint8_t value, uint8_t)
18
    {
19
      digitalWrite(stb, LOW);
20
      shiftOut(dat, clk, MSBFIRST, value);
21
      digitalWrite(stb, HIGH);
22
    }
23
24
    void begin()
25
    {
26
      pinMode(stb, OUTPUT);
27
      pinMode(clk, OUTPUT);
28
      pinMode(dat, OUTPUT);
29
      digitalWrite(stb, LOW);
30
    }
31
};
32
33
ShiftReg595 sr {7, 5, 6};
ungetestet
von Bruno V. (bruno_v)


Lesenswert?

Ralph S. schrieb:
> das - zumindest aus meiner Sicht -
> nichtblockierend ist.

Das Originalprogramm sieht eigentlich so aus, als wäre es ursprünglich 
nicht blockierend und ist dann "verbessert" worden.

polled_delay kann einfach radikal gekürzt werden und das letzte else in 
loop entfallen, dann läuft es schon perfekt.
1
uint8_t polled_delay(void)
2
{
3
uint32_t runtime = millis() - start; 
4
5
    if (runtime >= runspeed_get())
6
    {
7
      return 0x80;                   
8
    }
9
    return 0;
10
}

Um nicht jedesmal rauszuhauen, kann man loop geringfügig modifizieren
1
void loop()
2
{
3
  uint8_t mode;
4
  uint8_t set = 0;
5
  static uint8_t len;
6
  static uint8_t i= 0;
7
  static uint8_t last_mode = 0xff;
8
  static uint8_t *laufl_prog;
9
  
10
  mode = dipkey_get();
11
  if (mode != last_mode)
12
  {
13
    laufl_prog = progpointer_get(mode);
14
    len = laufl_prog[0];
15
    i = 0;
16
    set = 1;
17
    last_mode = mode;
18
  }
19
  else
20
  {
21
     if(polled_delay())
22
     {
23
       i++;
24
       if (i >= len) i = 0;
25
       set = 1;
26
     }
27
  }
28
  if(set)
29
  {
30
     sr.setvalue(laufl_prog[i + 1], 1);    // Ausgabe eines Leuchtmusters
31
  }
32
}
: Bearbeitet durch User
von Ralph S. (jjflash)


Angehängte Dateien:

Lesenswert?

Grüß Dich Arduino F.

Du hast natürlich Recht, millis() läuft nach knapp mehr als 2 Tagen über 
und deine Korrektur ist absolut richtig (habe ich jetzt geändert):

Grundsätzlich ist auch so etwas hier nicht notwendig (bzw. sogar 
"falsch"):
1
    void TIMERADC::setstarttime(void)

Ich muß den Klassenbezeichner hier nicht angeben und kann entfallen (was 
ich dann auch gemacht habe).

Zu der "Library" sn74hc595.h :

Da das Setzen/Löschen eines Pins genau ein einziges mal vorkommt ist 
ein:

> inline void datHigh() { digitalWrite(dat, HIGH); }

nicht notwendig und kann entfallen, wenn bei der Ausgabe dann direkt 
digitalWrite verwendet wird.

Du hast das so gemacht:

Arduino F. schrieb:
> void setValue(const uint8_t value, uint8_t)
>     {
>       digitalWrite(stb, LOW);
>       shiftOut(dat, clk, MSBFIRST, value);
>       digitalWrite(stb, HIGH);
>     }

und das funktioniert natürlich. Weil ich - wie du weißt - nicht wirklich 
Arduinoprogrammierer bin, kannte ich shiftOut schlichtweg nicht. Hier 
ist es sogar egal, (was mir mehr liegt) ob die Strobeleitung nach dem 
shiftOut komplett low-high gesetzt wird, was bei mir notwendig ist, da 
ich daraus dann tatsächlich eine kleine Erklärung für innerbetrieblichen 
Unterricht geben werde um Schieberegister kaskadieren zu können (hier 
wird dann nur beim letzten Ausschieben ein Strobe-Impuls gegeben).

Interessanterweise funktioniert shifOut auf AVR erwartungsgemäß korrekt, 
aber auf einem CH32V003 mit entsprechendem Core nicht (die "Library" 
hier jedoch schon). Aus diesem Grund verwende ich jetzt dann doch eher 
sn74hc595.

Arduino F. schrieb:
> Mal abgesehen von dem Stil, der nicht Ardoinotypisch ist,

Hier wird es schon etwas schwieriger! Ich denke mir schon, dass das 
nicht arduinotypisch ist und ich habe mir überlegt gehabt, wie man einen 
Event-Handler arduinotypisch anlegen könnte / kann und bin auf keine 
Idee gekommen.

Der grundsätzliche Gedankengang ist ja, dass der Handler in der loop 
immer wieder aufgerufen wird und die Funktionalitäten im Handler 
gestartet werden und eben nicht in der loop.

Das einzige was ich mir hier vorstellen kann ist, dass der komplette 
Handler in die loop gesetzt wird und alles nach dem do-while ist 
idle-Mode und dort kann weiteres hinzugefügt werden. Für mich stellt 
sich hier die Frage, ob das dann nicht noch unübersichtlicher wird.

Grundsätzlich freut es mich jedoch, dass der Handler so wie er ist, 
tatsächlich funktioniert. Natürlich wird bspw. das Einlesen eines 
Strings von uart, grundsätzlich wieder anderst vorgenommen, als 
arduinotypischerweise Serial.readln (welches meinen Handler blockieren 
würde).

Wenn du hier andere Gedankengänge / Ansätze hast würde ich mich schon 
darüber freuen, diese zu lesen!
von Ralph S. (jjflash)


Lesenswert?

By the way:

das hier wird zur Erklärung des Schieberegisters in der 
Falstad-Simulation herangezogen werden:

https://www.falstad.com/circuit/circuitjs.html?ctz=DwYwlgTgBAZgvAIgIwKgFwM6IAwDpsEECsqYIiSeATAVQOx0DM2AHFQGwCcndqIARoiLZUAB0EJhqAG4QhqALaYhAUwC0SFAD4AUFCjAAIgDEANmFFmA9qKgAPRBvZQk7bFEZUXb1PAQioaSR5AHpdfWAAJXtHJAAWOI9sRLV6L2Y43wpUAHc-Kl85ZAJFAEM7aUQqXBIofjBSrARqkjC9AxyYhDV2RKoWFignKH6WLP8ENojOh27XEYGh+aROAtgcSfCDABkutTjB13cNJC8j8bXRbKmOvYPvY+WfdYmb4Ds9zkT4xg8XOPY40yUAwYCqwLQKkQYAAdqIAK5oTbtd5dKiMX6MOiJNyJLG8F7A0Hg1CQxAsNQAITAaCgAGUQAALMAqfgqCAqADmYAwkOgChpUG2pTQTOREQAsl0Vl53DKhr0LuKDHS9r0FoMNAkNeMAldkKhzBt0IyqsrgBg9vLGCwUtbGICXpdslAFApEGgIPCVOboLMNKt-nbA1Q4gE-AEipQSm8ZrEQ2GliG6GsI+a43Nk14A+kHbr01as0ttWl829ov75fFg14WOHjXljQpypVJObOYX0rak144q4y1sjGYLNZbLNOM45dr6xNAsE27GunWoMvlzORIvZmuoBOoOuC1u5W4V+46wOUVLZqGj+5ry5VkrN4hd54d85NKmNk+ELuPyNEx+54RCY5iWKYNhoomt6LPuc6hIOGZ3q+d6AS8G4IZB7i3qGe5AbcV44dh3zPGmbwgSO4FjhQ-QPC4dDviRxpBPBKIZsuRxvg8eHABmv7HqchyMa8GGzAJ95nDRozcRmYmjEszhSWhB5VDhHEoUJ6EXl0fHuL+D5OspP7OK++yDJ43G7P69wmX+5kGVA+ooG8Hz+ruzipLpQKoMSzQQlCCC8hAVhsual6IBik4eA6CrAvkhkOoJ7g2sR+7fmkGouJJAzSWiKbiSMeWKaRIngjeBVnBp5rkWBEFXnlHGeDe+ZwQug5hQgyW0Z1MqPiVkinLRRA0ecSnfn2CmLOlRVfn1435XN03CaxXTdcec0jcVKLVaOXTrWt6obTNWmzENiVQKd4m9Vtw41VRP6BhxlAAZVLWtH1E5ldwFWpe9D2Bl9Oqjb9XhybagyLZpkrafxx4fZdBlkTdO1bvcHEsDpzXMa1y1bk8p6o5V35g-lxMQ4ZpOLHQySA5t0zadqHFw4dS1Q7M7D1ce7NnPpcVEwQtEsHjOWzFTfSLEQx5k9+ov5TLUt9VztEy8zkP4Yg7AS7Risq1VSOUV0yvHnQQ1cUDx3knjK7LDzZqI6ByNCDD7huIl3HtZo1OPU98O831lCLF7nuE31F0cRLTVm3TswLeLkvZZHauSPxgbhzTR2s4gBxYVAWcxVdwF67V4Xdu4cSvrBWNvTj4XsIMy4JbhCc8Sttd7h4JfCzXZ0N2eTcZp1r7dacncdd2f6h8PTfbfrJ00e4RD0Y3tOJxdr4T5+LMr3P50DT91f9bKO-fW7XTsIRUBnykioI21But+49GatfvvXfbM-q3lD80Ev6eJxrzjLn-j-Tezc2aa2dp-EeQCOJAN7svUBH90heG1pPeBGYUG1mWKg3+Q435FwQILSKLB1R7yjhbYymD3zYJAWxeYp5+akMTnWbOzDTbwPapwXeO4Bo9FirbW+olsDgJcEI9yz9+GvwovguGcoCCDArvOKuZCfzamXF8RIjCEEqI0W+LCI91G0QMXAnBvFjyviZtQ1WWiLFnG9qheB098Eex0ZoE2CiWLKOcR4WxntLGGS8bImCI9-byJEQHYO5tkA0GzqcfmvD86JxQgNIeG8rEZnXhfeqfiiZYK8DY88wAQjgAgLoIAA
von Ralph S. (jjflash)


Lesenswert?

Ralph S. schrieb:
> Du hast natürlich Recht, millis() läuft nach knapp mehr als 2 Tagen über
> und deine Korrektur ist absolut richtig (habe ich jetzt geändert):

... natürlich sind es 49 Tage: (2^32 / 86400) / 1000 = 49,71 Tage
von Horst (alteskind)


Lesenswert?

Die Simulation find ich super, das Programm werde ich morgen 
ausprobieren. Schieberegister müßte ich noch irgendwo haben.
von Veit D. (devil-elec)


Lesenswert?

Hallo,

Serial.readIn() gibt es nicht.
Du meinst Serial.read()?
Warum soll das blockierend wirken?
von Ralph S. (jjflash)


Lesenswert?

Veit D. schrieb:
> Serial.readIn() gibt es nicht.

du hast Recht, ich meinte aber eher: Serial.readString,

Mache einmal das hier:
[code]
String input;

.... in Setup

input.reserve= maxbufferlen;
input= "";

void loop()
{
  event_handler();

  // hier alle dem Event-Handler nachgeordneten Funktionen einfuegen
  if (Serial.available())
  {
    input = Serial.readString();
    Serial.print("Eingegangener String war: ");
    Serial.println(input);
    Serial.print("\n\r> ");
    input= "";
  }
}
[code]

dann wirst du feststellen, dass, so es keine Aktivität auf uart gibt, 
die Timer korrekt laufen. Gibst du ein Zeichen auf der Konsole ein 
(nicht der Monitor von Arduino), muß zum Einen sehr langsam getippt 
werden und zum anderen wird das Einlesen eines Strings bisweilen von 
einem NICHT gesendeten CR Zeichens der String abgeschlossen.

Außerdem hält hier das Lauflicht dann immer wieder einmal an.

Von daher ist es - für mich - besser, man erzeugt eine eigene 
Stringlesefunktion, verwendet NICHT die Klasse String und hat dann als 
"Regelverstoß" Arduino einen Mischmasch aus C, C++ und 
Arduinoeigenheiten (weil klassischerweise ein char stringbuffer[maxlen] 
verwendet wird).

Der Eventhandler liest immer nur ein Zeichen und setzt ein Flag, wenn 
ein String komplett eingelesen ist. Hier ist dann String natürlich ein 
Array of Char und kein Objekt der Klasse String. Den Eventhandler könnte 
man jetzt in der Art und Weise modifizieren, dass eine Funktion das 
gesetzte Flag strreadln_ready ausliest welches dann wiederum in 
event_scan ein Event auslöst. Hier müsste dann im Eventhandler als 
eigenes Event reagiert werden und wäre dann - entgegen den 
Arduino-Paradigmen - wieder nicht in loop zu sehen.
von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Ralph S. schrieb:
> wird das Einlesen eines Strings bisweilen von
> einem NICHT gesendeten CR Zeichens der String abgeschlossen.

Welch ein Unsinn .....

Ralph S. schrieb:
> Außerdem hält hier das Lauflicht dann immer wieder einmal an.
Serial.readString() ist blockierend.
Bis zum Zeilenende oder zum Timeout.

Ist also für deine Zwecke unbrauchbar.
String ist ok, solange genug Speicher dafür da ist.

Mein Rat:
Implementiere die "weak Function" serialEvent()
Lese mit Serial.read() ein!

Auch Serial.available() brauchst du nicht.
: Bearbeitet durch User
von Ralph S. (jjflash)


Lesenswert?

Arduino F. schrieb:
> Ralph S. schrieb:
>> wird das Einlesen eines Strings bisweilen von
>> einem NICHT gesendeten CR Zeichens der String abgeschlossen.
>
> Welch ein Unsinn .....

Kein Unsinn, denn, wie du hier schreibst:

Arduino F. schrieb:
> Bis zum Zeilenende oder zum Timeout.

Wird das durch Timeout automatisch erzeugt.

Grundsätzlich: Hier geht es nicht um Serial.read oder .print, sondern 
darum, einen Event-Handler zu verwenden um blockierendes zu vermeiden.

Aber ich erkenne, dass das alles nicht so wirklich zur 
Arduino-Philosophie passt.

Arduino F. schrieb:
> Mein Rat:
> Implementiere die "weak Function" serialEvent()
> Lese mit Serial.read() ein!
>
> Auch Serial.available() brauchst du nicht.

Mag sein, dass das so funktioniert. Die Methode einen eigenen Puffer zu 
haben finde ich dennoch übersichtler. Grundsätzlich habe ich das 
"eingefügt" um zu zeigen, dass der Event-Handler eben nichts blockiert 
und da war mir Serial.available ganz recht...

Leider leider leider bin ich jedoch jetzt "angetriggert", was man damit 
alles anstellen kann, ob und wie ich das gesamte Dokumentiere ( :-) mit 
dem Hinweis: "Nicht ganz Arduino konform" ) ... und ich bin am 
Überlegen, aus den Softwaretimern eine Library zu machen um den Sketch 
übersichtlicher zu machen. Außerdem würde hier dann meine Softwareuhr, 
basierend auf den Sekunden, die seit dem 01.01.1970 vergangen sind, 
relativ gut passend (mit Ausgleichssekunden für falsch laufende Quarze).

Grundsätzlich jedoch vielen lieben Dank (genau so gemeint) für die 
Anmerkungen von dir, sehr hilfreich um das Framework Arduino besser zu 
verstehen (und einige Vorbehalte und Voruteile auszuräumen). Ob ich 
allerdings ein "Fan" von Arduino werde, bleibt dennoch fraglich. 
Interessant ist es allemal, abseits von blink, delay und digitalWrite.
von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Ralph S. schrieb:
> Grundsätzlich: Hier geht es nicht um Serial.read oder .print, sondern
> darum, einen Event-Handler zu verwenden um blockierendes zu vermeiden.

Ich weiß!
Wenn du die falsche Methodik anwendest, schießt du dir selber ins Knie.

Ralph S. schrieb:
> Aber ich erkenne, dass das alles nicht so wirklich zur
> Arduino-Philosophie passt.

KA, was du damit meinst....
Ich kann dir zeigen, wie sowas bei mir aussehen könnte:
1
constexpr size_t maxBufferlen {80};
2
3
4
String input;
5
6
void serialEvent()
7
{
8
  int in = Serial.read();
9
  switch(in)
10
  {
11
    case '\r': /* fallthrough */
12
    case '\n': if(input.length())
13
               {
14
                 Serial.println(input);
15
                 input = "";
16
               }
17
               break;
18
    default:   input += char(in);  
19
  }
20
  if(input.length() >= maxBufferlen)
21
  {
22
    Serial.println("Zeile zu lang");
23
    input = "";
24
  }
25
}
26
27
void setup() 
28
{
29
  Serial.begin(9600);
30
  input.reserve(maxBufferlen);
31
}
32
33
void loop() 
34
{
35
36
}
von Alexander (alecxs)


Lesenswert?

Ralph S. schrieb:
> bin am Überlegen, aus den Softwaretimern eine Library zu machen

für wen?

Ralph S. schrieb:
> ob und wie ich das gesamte Dokumentiere

für wen?
von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Ralph S. schrieb:
> Kein Unsinn, denn, wie du hier schreibst:

Du haust dir selber mit dem Hammer auf den Daumen.
Und beschwerst dich dann, dass es weh tut.

Mag sein, dass dir das gefällt, aber ich halte das für unsinnig.
: Bearbeitet durch User
von Ralph S. (jjflash)


Lesenswert?

Arduino F. schrieb:
> switch(in)
>   {
>     case '\r': /* fallthrough */
>     case '\n': if(input.length())
>                {
>                  Serial.println(input);
>                  input = "";
>                }
>                break;
>     default:   input += char(in);
>   }

Das hier ist prinzipiell das, womit ich leben kann / könnte und 
zumindest von der Methodik her nicht so wirklich anderst, als das, wie 
mir das vorschwebt. Hmmm... Nur dass du dann dann ein Objekt String 
(großgeschrieben) mit seinen eigenen "Verwaltungsmethoden" hast. Dieses 
dürfte dann einer der Gründe sein, warum das ganze irgendwann zu einem 
Resourcenfresser wird (und warum die Boards für Arduino immer größer 
werden). Ich schaue mir mal an, was die class String so alles zu bieten 
hat, in Arduino ist ja scheinbar die <string.h> verpönt.
von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Ralph S. schrieb:
> in Arduino ist ja scheinbar die <string.h> verpönt.

Ist sie nicht!
Leider ist bei dem AVR-GCC die libstdc++ nicht dabei.
Damit gibts kein std::string
Verpönt ist nicht das gleiche, wie unmöglich.

Die 32Bit und 64Bit Arduinos oder auch Fremdprodukte haben std::string 
durchaus dabei.

Ralph S. schrieb:
> Nur dass du dann dann ein Objekt String
> (großgeschrieben) mit seinen eigenen "Verwaltungsmethoden" hast. Dieses
> dürfte dann einer der Gründe sein, warum das ganze irgendwann zu einem
> Resourcenfresser wird (und warum die Boards für Arduino immer größer
> werden).

Ähh....
Du hast eine rege Fantasie!
Keiner sagt, dass du String verwenden musst.
Du kannst durchaus deine heiß geliebten C-Strings verwenden.

In Arduino kannst du alles verwenden, was in C/C++ ASM geht.

Das schöne ist, dass String unendlich oft getestet wurde.
Und z.B. RAII implementiert.
Soweit ich mich erinnern kann, sagt sizeof 6 Byte zu String
von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Ralph S. schrieb:
> in Arduino ist ja scheinbar die <string.h> verpönt.

In der Arduino.h findet sich
#include <string.h>

Die Nutzung der dortigen Dinge ist also standardmäßig 
aktiviert/vorbereitet.
Habe keine Hemmungen, das zu nutzen.
Auch String bedient sich da.
von Hans (ths23)


Lesenswert?

Ralph S. schrieb:
> Nach meinen Kriterien hätte ich 1,5 gegeben ... auch wegen
> "Flüchtigkeitsfehler" in den Kommentaren:
Er hat's gut kommentiert und die würde ich gar nicht bewerten, es sei 
denn es war in der Aufgabenstellung verlangt.
Wenn die Aufgabenstellung wie gefordert umgesetzt wurde, dann ist das 
ein sehr gut, also besser als 1,5 und wenn da besondere Schmankerl 
eingebaut wurden, dann ist das halt noch ein bissel besser eine 1,3 oder 
1,2.
Warum muß bei Projekten immer das Haar in der Suppe gefunden und die 
Arbeit dann überproportional abgewertet werden.
Ich kenne das noch als meine Tochter zur Schule gegangen ist. Wenn dort 
ein Projekt anlag, dann war da nie mehr als eine 2 drin - irgendwas hat 
der Lehrer immer gefunden und da waren Dinge dabei die an den Haaren 
herbeigezogen waren.
Wenn eine 1 niemals erreichbar ist, dann ist das wenig motivierend und 
wir müssen uns nicht wundern, wenn die jungen Leute die Lust verlieren.
von Veit D. (devil-elec)


Lesenswert?

Hallo Ralph,

Arduino typisch ist eigentlich setup() und loop(). Daran erkennt man das 
Arduino Framework. Ob man dann die vorhandenen Libs/Funktionen/Methoden 
verwendet, das ist einem selbst überlassen, vereinfacht jedoch vieles.

Echte Strings machen nur Probleme, wenn man reserve() nicht verwendet 
bzw. zu klein gewählt wurde und dann den String ständig modifiziert. 
Halte dich an das Gesagte von Arduino F.

Noch ein Bsp. ohne String mit char Array, ganz klassisch. Die Funktion 
readline() ist wiederverwendbar, also unabhängig der Schnittstelle und 
Buffer.
1
Stream &cout0 {Serial};
2
Stream &cout3 {Serial3};
3
4
constexpr byte READ_BUFFER_SIZE {20};   
5
6
struct SerialDaten {           
7
  char buffer [READ_BUFFER_SIZE + 1];       // Platz für 20 Zeichen + Null-Terminator
8
  size_t index {0};
9
};
10
11
SerialDaten rx0Daten;
12
SerialDaten rx3Daten;
13
14
void setup()
15
{
16
  Serial.begin(9600);
17
  Serial3.begin(9600);
18
}
19
20
void loop()
21
{
22
  // liefert true wenn das LF eingelesen wurde
23
  if (readLine(cout0, rx0Daten) ) {
24
    cout0.print("Eingelesen cout0: ");
25
    cout0.println(rx0Daten.buffer);
26
  }
27
28
  if (readLine(cout3, rx3Daten) ) {
29
    cout3.print("Eingelesen cout3: ");
30
    cout3.println(rx3Daten.buffer);
31
  }
32
}
33
34
bool readLine(Stream &stream, SerialDaten &rx)
35
{
36
  bool status {false};
37
38
  while (stream.available()) {
39
    const char c = stream.read();
40
    if (c == '\n') {                                     // wenn LF eingelesen
41
      rx.buffer[rx.index] = '\0';                        // String terminieren
42
      rx.index = 0;
43
      status = true;                                     // String fertig eingelesen
44
    }
45
    else if ( (c >= 32) && (rx.index < READ_BUFFER_SIZE) ) { // solange noch Platz im Buffer ist
46
      rx.buffer[rx.index++] = c;                             // Zeichen abspeichern und Index inkrementieren
47
    }
48
  }
49
  return status;
50
}

Nochwas, eine Bitte an dich selbst. Lass einmal dein negatives Gerede 
weg. Wenn dich Arduino nervt dann lasse es. Wenn du damit umgehen 
möchtest, dann lerne es. Kann ja nicht so schwer sein wenn man DMA 
beherrscht. ;-) Wenn sich jemand immer wieder über irgendwas beschwert, 
irgendwelche Kleinigkeiten, die gar keine Rolle spielen bzw. falsch 
sind, bspw. Serieller Monitor oder wegen Strings angeblich größer 
werdende Boards, dann nervt das und man verliert die Lust noch irgendwie 
überhaupt Hilfe zu leisten.
: Bearbeitet durch User
von Alexander (alecxs)


Lesenswert?

Am Ende ist das nur Beschäftigungstherapie. Es gibt gar kein Lauflicht.
von Veit D. (devil-elec)


Lesenswert?

Hallo,

noch ein anderes Bsp. für Events, wenn das millis() Intervall gültig 
wird. 0xEFFFFFFF ist eine künstliche "Überhöhung", damit gleich nach µC 
Reset das  Event ausgelöst, statt mit 0 initialisiert. Macht etwas 
sinnvolles damit. :-)
1
/*
2
  Devil-Elec - µC.net
3
  IDE 1.8.19
4
  avr-gcc: 7.5.0 & C++17
5
  Arduino Mega 2560
6
  04.05.2026
7
*/
8
9
template<typename Callback>
10
class SimpleTimer
11
{
12
  private:
13
    unsigned long lastMillis {0xEFFFFFFF};
14
    unsigned long duration   {0};
15
    Callback callback;
16
17
  public:
18
    SimpleTimer (unsigned long d, Callback cb):
19
      duration(d),
20
      callback(cb)
21
    {}
22
23
    void update() {
24
      if (millis() - lastMillis >= duration) {
25
        lastMillis = millis();
26
        callback();  
27
      }
28
    }
29
};
30
31
SimpleTimer timerA (1000, []() {
32
  Serial.println("A");
33
});
34
35
SimpleTimer timerB (2000, []() {
36
  Serial.print("B ");
37
});
38
39
void setup (void)
40
{
41
  Serial.begin(9600);
42
  Serial.println("\nuC Reset ###\n");
43
}
44
45
void loop() {
46
  timerA.update();
47
  timerB.update();
48
}
: Bearbeitet durch User
von Ralph S. (jjflash)


Lesenswert?

Veit D. schrieb:
> Nochwas, eine Bitte an dich selbst. Lass einmal dein negatives Gerede
> weg. Wenn dich Arduino nervt dann lasse es. Wenn du damit umgehen
> möchtest, dann lerne es. Kann ja nicht so schwer sein wenn man DMA
> beherrscht. ;-)

Einen Vorschlag zur Güte (weil du hier gerade tatsächlich Recht hast): 
Ich lasse das weg und Du läßt es, mich wie einen Stümper dastehen zu 
lassen. Das wäre doch glatt eine Win-Win Situation. Außerdem habe ich ja 
auch gesagt, dass ich bestimmte Vorurteile gegenüber Arduino beiseite 
schiebe und manche Dinge darin "gar nicht schlecht sind" (und das von 
jemandem - der sich bisher dagegen gesträubt hat, schlicht weil ich 
viele Beispiele von Leuten gesehen habe, die wohl wirklich absolutes 
Anfängerniveau haben. Was ich explizit von Dir und Arduino absolut NICHT 
behaupte. Ihr seid offensichtlich extrem tief in dieser Materie drin).

Hand zur Güte reiche!
von Veit D. (devil-elec)


Lesenswert?

Hallo Ralph,

es war nie meine Absicht dich als Stümper o.ä. dastehen zulassen. 
Wirklich. Ich sprach nur direkt an was mir auffiel. War zu direkt, okay, 
habe es verstanden. Ich habe das auch nie für mich so böse gesehen, 
deswegen habe ich auch im Thread weiterhin gelesen und geantwortet. 
Okay, manchmal wollte ich dich necken, aber eher zum Spass. Habe 
verstanden, kam nicht so gut an.
Handshake von mir jederzeit. Kein Problem. Ich werde versuchen weniger 
direkt zu sein. :-)
von Ralph S. (jjflash)


Lesenswert?

:-) alles gut
von Veit D. (devil-elec)


Angehängte Dateien:

Lesenswert?

Hallo Ralph,

ich hatte mich nochmal hingesetzt und mir Gedanken gemacht wie man das 
vielleicht aufgeräumter hinbekommt. Das Schiebregister habe ich 
weggelassen, ich denke das Schema wird auch so ersichtlich. Hier nutze 
ich Lambda Funktionen, sodass am Ende in der loop nur immer eine Timer 
Methode Namens update() aufgerufen werden muss.
Hier im Bsp. werden mit 50ms Entprellzeit die DIP Switche abgefragt.
Im 100ms Rhythmus wird das Poti eingelesen und gefiltert.
Im 1s Rhythmus wird ein aktueller Wert Serial ausgegeben.
Das kann man fortführen oder auch nicht. :-)
Man kann Hunderte DIP Switch Instanzen anlegen.
Man kann Hunderte Poti Instanzen anlegen.
Verknüpft diese mit einer Timer Instanz und lässt sie ihr Ding machen.
Das Einzigste was Arduino Nutzer machen müssen, ist eine Compiler 
Einstellung auf C++17 statt Standard C++11.
Dort wo die platform.txt liegt eine platform.local.txt anlegen und diese 
Zeile einfügen.
1
compiler.cpp.flags=-c -g -Os {compiler.warning_flags} -std=gnu++17 -fno-exceptions -fpermissive -ffunction-sections -fdata-sections -fno-threadsafe-statics -Wno-error=narrowing -MMD -flto
Dann muss man nicht in der Originalen rumfummeln.
: Bearbeitet durch User
von Alexander (alecxs)


Lesenswert?

Ihr habt echt Langeweile. Ich hätte hier genug zu programmieren und 
kann's nicht.
von Veit D. (devil-elec)


Lesenswert?

Hallo Alex,

jeder kann irgendwelchen Blödsinn lernen. Auch du. :-)
von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Veit D. schrieb:
> Auch du. :-)

Nein!
Das glaube ich nicht.
von Oliver S. (oliverso)


Lesenswert?

Veit D. schrieb:
> ich hatte mich nochmal hingesetzt und mir Gedanken gemacht wie man das
> vielleicht aufgeräumter hinbekommt.

> template<uint8_t pin, uint8_t FF>
> …

> ** FF = Filterfaktor;
1
template<uint8_t pin, uint8_t Filterfaktor>

Selbstdokumentierender Code macht’s einfacher.

Oliver
von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Oliver S. schrieb:
> Filterfaktor

FilterFactor

English ist zu bevorzugen.
Machts für den Rest der Welt leichter zu lesen.
Die KamelHöckerSchreibweise hilft Missverständnisse zu vermeiden.
von Alexander (alecxs)


Lesenswert?

Veit D. schrieb:
> Hallo Alex,
>
> jeder kann irgendwelchen Blödsinn lernen. Auch du. :-)

https://pastebin.com/JxxjtKaX
von Rbx (rcx)


Lesenswert?

Lehrer können despotisch sein. Wer kennt das nicht? In Hannover hat mal 
ein Lehrer sogar mehrere Leute umgebracht und zerstückelt.
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.