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!
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.
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.
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:
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?
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...
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.
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.
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.
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.
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!
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.
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.
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.
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.
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.
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.
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
intrunspeed_get(void)
2
constintspeedctrl=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.
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.
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.
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.
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_tpolled_delay(uint8_tdipkey_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.
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.
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
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.
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.
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. ;-)
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.
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.
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 ;)
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.
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.
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!
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.
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.
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.
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.
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)
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.
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.
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.
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.
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.
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.
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.
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.
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. ;-)
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.
Du zitierst falsch. Sehr falsch sogar.
Was intern passiert, hat mit der Frage nach dem irreführenden Namen nichts zu tun.
Ich will kein Zeitraster. Ich weiß noch nicht einmal wo du das gelesen haben willst.
Ich benutze das Zeug nicht. Dennoch muss eine solche Frage legitim sein.
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?
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.
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".
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.
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.
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!
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.
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.
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.
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
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.
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
constexprbyteREAD_BUFFER_SIZE{20};
5
6
structSerialDaten{
7
charbuffer[READ_BUFFER_SIZE+1];// Platz für 20 Zeichen + Null-Terminator
8
size_tindex{0};
9
};
10
11
SerialDatenrx0Daten;
12
SerialDatenrx3Daten;
13
14
voidsetup()
15
{
16
Serial.begin(9600);
17
Serial3.begin(9600);
18
}
19
20
voidloop()
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
boolreadLine(Stream&stream,SerialDaten&rx)
35
{
36
boolstatus{false};
37
38
while(stream.available()){
39
constcharc=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
elseif((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
returnstatus;
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.
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. :-)
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).
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. :-)
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.
muss noch eine kleine Korrektur erledigen. newValue in der AnalogRead Klasse war "doppelt". Habe mich dabei für die Beibehaltung von readAnalog() entschieden.
ich wollte soeben das Programm erweitern, da fiel mir auf, dass das Timing nicht stimmt. Eigentlich hatte ich damit noch nie Probleme. So schief kann der Resonator vom Arduino Mega2560 Board nicht takten. Daraufhin habe ich den Sketch auf das Minimum reduziert und das Problem bleibt. Das Intervall von 1s ist meistens kürzer und zwischendrin 20, 30ms länger. Solche Abweichungen mit so einem simplen Sketch sind mir bis heute nicht bekannt. Das es manchmal paar ganz wenige ms größer ist normal, aber kürzer? Übersehe ich irgendwas? Oder täuscht mich alles und es ist normal so?
1
classSimpleTimer
2
{
3
private:
4
unsignedlonglastMillis{0xEFFFFFFF};// provoziert eine sofortige Auslösung nach uC Reset
Ernsthaft? Gibt's Erkenntnisse weshalb das passiert?
Hier getestet, Daten kommen auf die Millisekunde genau an.
Also ich bin mir ziemlich sicher dass ich das auch bei mir schon beobachtet habe und ich schließe da den Fehler des absendenden uC aus.
Und ich habe es auch mit Linux und irgendeinem USB-seriell Wandler laufen gehabt. Du hast wahrscheinlich einen Raspberry Pi Pico genommen?
Aber da du ja schon ein Testprogramm gepostet hast fühle ich mich jetzt genötigt das zu testen. ;) Aber vermutlich nicht mehr heute. Aber morgen.
Anderer PC, anderes Debian (13,Trixie), anderer PICO (China Klon)
Gleiches Ergebnis, na ja fast, 2ms Varianz (vmtl. wegen der laufenden OBS Aufnahme)
Hab die Änderung für UART mal angehängt.
Hier getestet, Daten kommen auf die Millisekunde genau an.
Ist bei mir unter Linux hier auch so. Gesehen hab ich es aber schon. Aber was da dann der Grund war kann ich jetzt auch nur in die Glaskugel schauen.
Wenn ich noch genau wüsste bei welcher Spielerei, hätte ich es auch nochmal ausprobiert.
Aber egal, einen Portpin schalten und das mit dem Scope zu messen ist dann die sichere Variante das Timing zu testen.
also Pin Toggle passt. Oszi zeigt stabile Werte an. Soweit alles normal. Also erzeugt Windows eine Miniverzögerung. Hätte ich jetzt nicht gedacht. Danke.
Edit:
Also nur an Windows liegt es nicht. Wird wohl allgemein am OS hängen. Denn unter Fedora KDE habe ich ähnliches Verhalten. Generell immer leichter unter 1s. Oben sieht einen Sprung .245 > .237 > .265, weiter runter Mitte erneut .237 > .265
also Pin Toggle passt. Oszi zeigt stabile Werte an. Soweit alles normal.
Also erzeugt Windows eine Miniverzögerung. Hätte ich jetzt nicht
gedacht. Danke.
Edit:
Also nur an Windows liegt es nicht. Wird wohl allgemein am OS hängen.
Denn unter Fedora KDE habe ich das gleiche Verhalten.
Vielleicht hat's auch einfach nur mit dem Verhalten der Arduino IDE zu tun.
Schon mal alternativ mit CuteCom und dessen Timestamp Mechanismus getestet?
es ist deutlich stabiler, aber nicht so astrein wie bei dir.
Ist schon irgendwie irre. ;-) Danke für den Tipp.
Ich glaube die Beweisaufnahme ist damit abgeschlossen.
habe es erweitert. Wirkt vielleicht etwas kompliziert, mag sein, dient aber nur einem handfesten Zweck, keine händische Berechnung und Eintragung im Array für irgendwelche Array Größen für das eigene Array. Das ist der Ursprungsgedanke für den Aufwand. Daraus folgend ist der Programmcode der das selbstständig erledigt. Vielleicht gibt es hier und da noch Ecken wo man aufräumen könnte, mag alles sein. Der Knackpunkt war der Umgang mit unterschiedlichen Array Größen. Im Lambda Ausdruck der Instanz timerLauflicht oder einer extra Funktion müsste dann die Übergabe des aktuellen Wertes an das echte Schieberegister erfolgen. Das was aktuell mit Serial "BMP 0x" ausgegeben wird. Wenn man am Poti dreht ändert sich die Ausgabegeschwindigkeit und wenn man die DIP Switche ändert (ich drücke Tasten), wechselt das Array woraus die Werte ausgelesen werden.
Mehr mach ich nicht, abgesehen von Fehlerbehebung. ;-)
Hmmmm... Veit, ich habe da so etwas draus gemacht (und ist noch nicht vollständig dokumentiert... wollte ich aber erst gar nicht hier einstellen, jetzt aber doch)...
Wenn ich die Doku fertig habe, werde ich das als Projekt hier veröffentlichen... hier jetzt aber nur mal (die größere Menge) Sources....
... mit dem eigentlichen Sketch, der die Libs halt eben braucht ... Eventsources spielen da eine Rolle, bei dem Gedanken von Arduino F. von dem Thread hier mit reinfließen.
Das ganze ist ein "Interruptloses eventgesteuertes System" welches nichtblockierend ist und auf einem Terminal (nicht Serialmonitor aus Arduino) Kommandos entgegen nehmen kann und auf die der Controller reagiert.
Es wird gesteuert, ob die Eingabezeile den "Fokus" hat oder eine eventuell laufende Funktion. Grundsätzlich wird zudem aus millis() eine Hardwareuhr gebildet, die sich an der Unix-Zeit und dem Zeitstempel aus Unix orientiert. Im übrigen (getestet) läuft die uhr nach 5 Tagen ca. 8 bis 10 Sekunden falsch, was wohl dem Quarz des Arduino geschuldet ist (ich hatte das schlechter erwartet).
smile , ich weiß: eine Menge Dateien und eine Menge zu kritisieren.
Mir ging es hier um das eventgesteuerte System.... prinzipiell habe ich ähnliches mit einem STM32F4 mit Interrupts schon gemacht.
Und ja, das ist einfach nur eine Demo.... smile, wie du weißt: ich lerne jetzt sogar noch Besonderheiten von Arduino... meinen Programmierstil... gewöhnt man mir in meinem Alter nicht mehr ab.....
Und grundsätzlich: das hier ist prinzipiell an das uralte TurboVision System aus Borland C++ angelehnt.... Eventnumber, Eventhandler, Idle .... und er Interrupt wird durch eventscan ersetzt, der praktisch permanent pollt, ob ein Event (gerne von millis() ausgelöst) aufgetreten ist.
Aber wenigstens weiß ich nun
warum man einen STM-32 für ein Lauflicht nimmt :-). da geht bestimmt
noch mehr.
es ging hier nicht um die Hardwareplattform, für ein Lauflicht reicht jeder Controller, von PFS154 über MCS-51 ..... oder jeder Controller der in Arduino funktioniert (dann fallen PFS154 und MCS-51 raus, weil es für die keinen Core gibt der C++ kann)
sieht erstmal okay aus. Haste dir Mühe gegeben. :-)
Du verwendest viel constexpr, sehr schön, da kannst du die letzten define Variablen auch constexpr machen. ;-)
Beim kompilieren fallen paar Dinge auf, die zukünftig Probleme bereiten können.
bei dem Gedanken von Arduino F. von
dem Thread hier mit reinfließen.
Ich danke dir für die Erwähnung.
Muss aber bemerken, dass du nicht viele meiner Vorschläge übernommen hast.
Das ist natürlich kein echtes logisches/Programm Problem. Aber dennoch etwas überraschend für mich. Obwohl du vorher irgendwann mal gesagt hast, dass du deinen Stil gegen alle Widerstände beibehalten willst.
Schlussendlich, alles OK, denn es ist ja dein Programm, und nicht meins.
Muss aber bemerken, dass du nicht viele meiner Vorschläge übernommen
hast.
Sagen wir es einmal so: es gab da schon einige Sachen die ich da im Hinterkopf hatte... fängt mit der loop an (kein while (1) dort)... irgendwo anderst nicht hier , hast du geschrieben: würde den stream erwarten ... von daher. Zudem habe ich mir bspw. die Klasse String angesehen und du meintest es wäre absolut erlaubt, meine "heißgeliebten Ascii-Z Strings" zu verwenden. Außerdem habe ich angefangen in einem anderen "Projekt" doch tatsächlich auch innerhalb eines Sketches eine Klasse zu definieren (und nicht nur in einer Lib). Allerdings weiß ich nicht, ob Anfänger damit zurecht kommen (die Rückmeldungen die ich da habe sind eher nicht positiv) . Einige deiner Vorschläge behalte ich im Hinterkopf, wenn es um Arduino geht. Grundsätzlich hat sich dafür meine Meinung über Arduino geändert. Die Prämisse heißt nicht mehr Arduino gegen Embedded oder C oder ähnlich, sondern eher "Parallelexistenz" .... (auf anderer Ebene praktiziere ich das bspw. auch: Nicht Delphi (Lazarus) oder C++ (QT5), sondern sowohl als auch.
@Veit... hier ging es mir in erster Linie um das "Eventsystem" ... die anderen Teile sind schon älter und die werde ich wohl alle noch, wenn Sinnvoll, umarbeiten...
Das halte ich für gefährlich. Was passiert wenn v Parameter 0 ist?void
dice_show(uint8_t v)
{
uint16_t m = diceint[v - 1];
textcolor(v+8);
for (int i = 0; i < 15; i++)
{
if (m & (1<<(15-i))) printf("o"); else printf(" ");
if (i % 5 == 4) printf("\n\r");
}
textcolor(7);
printf("\n\r");
}
:-) zum einen ist das ja "nur" Demo für das Eventsystem und zum anderen seh dir an, wer dice_show aufruft und unter welchen Bedingungen. Von den Zufallsbedingungen wird dice_show niemals mit 0 aufgerufen werden, aber natürlch könnte man den Fall "0" abfangen, die Frage lautet nur: warum, wenn 0 nicht auftritt.
Anderst wäre es, wenn das ein universelles Modul wäre oder dergleichen.
Ich erhalte das "Menü" siehe Bild.
Keine weiteren Ausgaben.
Led13 blinkt. Schieberegister funktioniert, reagiert auf Modiwechsel und Poti-Geschwindigkeitsänderung. :-)
Mit 'stb' musste ich überlegen, ist eine andere Bezeichnung wie 'LATCH' bzw. 'STCP'. Du könntest noch eine Resetfunktion mit '/MR' Pin einbauen.
NTC ist nicht dran.
Poti an A0.
Verwendet wird ein Arduino Mega2560.
Soweit so gut.
Warum nichts weiter im Terminal erscheint weiß ich noch nicht.
Außerdem habe ich angefangen in einem
anderen "Projekt" doch tatsächlich auch innerhalb eines Sketches eine
Klasse zu definieren (und nicht nur in einer Lib). Allerdings weiß ich
nicht, ob Anfänger damit zurecht kommen (die Rückmeldungen die ich da
habe sind eher nicht positiv).
Das lässt sich für Neulinge einfach erklären. Eine Library ist erstmal nichts weiter wie ausgelagerter Code, meist mit dem Ziel der Wiederverwendbarkeit. Das betrifft nun einmal vorwiegend Klassen. Wo diese stehen, ob im Hauptsketch oder Library ist erstmal egal. Meistens entwickelt man am Anfang im Hauptsketch und lagert es später aus bzw. wenn die Klasse wächst.
Und eine Struktur, was auch nur eine Klasse ist, nur meistens nicht so bewusst gesehen wird, hat jeder ziemlich schnell in der praktischen Anwendung. Und ratz fatz weiß jeder was eine Klasse ist. Ich würde mit einer Struktur anfangen, diese einfach anwenden, dann Methoden hinzufügen und wenn das klar ist auf class wechseln und klar machen das sich die Sichtbarkeit ändert und wie man das steuert. Dann sollte das schon jeder verstehen, unabhängig wo die Codezeilen lagern.
weil ich hier ja nichts anderes zu tun habe (immer noch nicht zu Hause), kann ich hier viel experimentieren. Meine Frau hat die richtige Box mitgebracht in der auch die von mir nicht verwendeten Arduinos drin liegen, namentlich u.a. ein Arduino Due und ein Arduino Mega2650.
Zudem hat sie mir auch noch das zweite alte Notebook mitgebracht auf dem Win10 drauf ist (mit dem Kommentar von ihr: du spinnst doch). Wie dem auch sei, ich habe jetzt ein Testequipment und kann nicht nachvollziehen, warum in deinem Teraterm-Fenster das nicht geht.
Den Code des Eventhandlers (und nur den) habe ich jetzt einmal leicht angepasst (und die anderen von dir angemerkten Dinge noch nicht).
Zudem habe ich, weil du Tera Term auf deinem Rechner hast, das hier auch installiert und das ganze ausprobiert.
Es läuft auf Arduino Uno / Nano / Due / Mega2650 und CH32V003 (ich weiß von vor dem Unfall, dass das auch auf STM32 läuft, habe ich aber hier nicht zum testen).
Hast du im Fenster des Terminals versucht etwas einzugeben? Im Terminal kannst du eben den Dispatcher ja unterschiedliche Funktionen aufrufen, den Sketch habe ich dahingehend verändert, dass beim Start angezeigt wird, welche Kommandos eingebbar sind (während das Blinklicht und das Lauflicht weiter munter vor sich her werkeln).
So, hier habe ich jetzt das ganze mal mit angehängt, dieses mal als gezippte Libraries, die du ja wieder einfach löschen kannst, wenn du dir das ganze angesehen hast.
Eine Library ist etwas umfangreicher die eigentlich gar nicht gebraucht wird: extended_serial.zip. Sie ist deswegen mit dabei, weil dort 2 .cpp Dateien enthalten sind, wovon eine benötigt wird, wenn man das ganze für einen ch32v003 machen möchte.
:-) vllt. hast du ja noch einmal die Muse, das ganze bei dir laufen zu lassen. Eingebbare Befehle siehst du im Screenshot des Terminalfensters (ich habe das Kommand "list" mit hinzugefügt).
Soweit funktioniert der Sketch. Auf Tasten reagiert er nicht, dafür auf Terminaleingabe für den Led Moduswechsel. Bestimmt so gewollt.
Und wegen
1
(mit dem Kommentar von ihr: du spinnst doch)
du bist damit sinnvoll beschäftigt und kommst nicht auf dumme Gedanken mit den Krankenschwestern. ;-) Sie wird dir alles mitbringen was du möchtest. :-) Wünsche gute Genesung.