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!
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.
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?
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.
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
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!
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...
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?
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'.)
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?
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.
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!
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).
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.
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.
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
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 };
|
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
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.
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.
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.
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
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.
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.
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.
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
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.
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
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.
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.
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. ;-)
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).
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.
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
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 ;)
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.
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.
Sind doch nicht meine Hausaufgaben. Das beurteilen überlasse ich lieber den Experten.
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.
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.
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.
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.
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.
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!
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.
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.
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.
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.
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
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)
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.
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.
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.
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 ;)
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?
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.
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.
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 | }
|
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
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.
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 ;)
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 | }
|
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 | }
|
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
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.
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
Arduino F. schrieb: > Ja, nee.... 0kay, ein Missverständnis. Aus dieser Glaubensfrage halte ich mich raus.
Norbert schrieb: > Wieso heißt die Funktion bei Arduino eigentlich ›loop()‹ Wurde geerbt wie vieles andere auch. Und modifiziert Vorbild: https://processing.org/reference
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.
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.
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
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?
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.
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.
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".
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
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
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
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!
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
Die Simulation find ich super, das Programm werde ich morgen ausprobieren. Schieberegister müßte ich noch irgendwo haben.
Hallo, Serial.readIn() gibt es nicht. Du meinst Serial.read()? Warum soll das blockierend wirken?
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.
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
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.
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 | }
|
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?
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
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.
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
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.
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.
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
Am Ende ist das nur Beschäftigungstherapie. Es gibt gar kein Lauflicht.
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
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!
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. :-)
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
Ihr habt echt Langeweile. Ich hätte hier genug zu programmieren und kann's nicht.
Hallo Alex, jeder kann irgendwelchen Blödsinn lernen. Auch du. :-)
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
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.
Veit D. schrieb: > Hallo Alex, > > jeder kann irgendwelchen Blödsinn lernen. Auch du. :-) https://pastebin.com/JxxjtKaX
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.