Achso, jetzt fällt es mir erst auf. Beim Wort "Unterprogramm". Du bist der von letztens mit den gotos.
Ja, da wundert das nicht.
Achso, jetzt fällt es mir erst auf. Beim Wort "Unterprogramm". Du bist der von letztens mit den gotos.
Ja, da wundert das nicht.
Was soll das heißen?
Ich kann mir kein umfangreiches Programm ohne UP's vorstellen. Das trägt doch eindeutig zur Übersichtlichkeit bei, wenn es mal klappt. Außerdem können große Programmteile übersprungen werden, die für einen bestimmten Ablauf nicht benötigt werden und verkürzen dadurch die Programmlaufzeit.
Außerdem springe ich mit goto nicht nach vorne , sondern nur nach hinten!!
vG
fredyxx
- - - Aktualisiert - - -
ja, ist mir bekannt, habe ich vor kurzem erst noch praktiziert1) = statt == in logischen Abfragen
werde ich prüfenbreak in switch-Blöcken vergessen
Habe ich nicht verwendetArrayindex größer als Arraygröße
werde ich prüfen4) Integerdivision und 5) Division durch Null
Was ist das?Nicht inizialisierte Pointer
??falsche Schleifenbedingung
vG
fredyxx
Geändert von fredyxx (14.09.2016 um 16:30 Uhr)
Davon hatte ich auch nichts gesagt.
Sondern das was in "void Setup()" steht nach "void loop()" zu verschieben.
Also
void Setup() {
bla
bla
von hier
bla
bla
}
void loop() {
nach hier
code
code
noch mehr code
}
Bei Arduino wird "void Setup()" immer genau einmal beim Start ausgeführt. "void loop()"dagegen wird in Endlosschleife ausgeführt bis der Strom weg ist ode rein Reset erfolgt.
"void Setup()" kann man also sogar gezielt dazu nutzen um einen Code beim Einschalten immer genau einmal auszuführen.
wenn Du allerdings mit Gotos um dich wirfst, dann ist Das was Du bekommen hast nicht weit.
Gotos kann man nehmen wenn man damit klar kommt.
Bei Assembler hat sogar nur Jump (also Goto) aber da muß man halt aufpassen das man auch immer wirklich da raus kommt wo man hin will (also zu der Situation)
Um code in bestimmten Situationen zu überspringen gibt es z.B. IF und CASE. Da ist Quasi ein GOTO eingebaut.
Dann gibt es noch Funktionen und Subroutinen (was Du Unterprogramme nennst). Bei einem Microcontroller mit genau einem Programm im Speicher gibt es keine Unterprogramme.
Die Hauptschleife void loop() enthällt dann den code der immer durchlaufen werden muß und der Rest ist in Funktionen ausgelager.
Das spart Laufzeit und verhindert Spagetti Code.
Das von mir vorgeschlagene Verlagern der Initialisierung wird demnach vermutlich nichst bringen, kannst Du also lassen.
Geh mal die Fehlersuche von Sisor durch und druck dir deinen Code aus.
Dann nimm Textmarker und makiere alle Funktionsblöcke vom Beginn "{" bis Ende "}".
Hast Du richtig codiert, darf sich keine Linie mit einer anderen überschneiden.
Dann nimm Deine GoTOs und Deine Sprungmarken die Verbindungen dürfen dann auch nicht in verschiedenen Funktionsblöcken liegen.
Wenn Ja liegt eigentlich ein bedingter Sprung vor also mußst Du vor dem GOTO oder nach der Sprungmarke dafür sorgen das die Bedingungen auch in jedem Fall immer erfüllt werden.
Lustig wird es wenn von mehreren Gotos auf eine Sprungmarke gesprungen wird und dabei X Bedingungen vorliegen weil Variablenwerte nicht mehr korrekt verändert werden.
Da ich sehr viele Quick and dirty Batch Scripte in Windows Umgebungen schreibe, bin ich mit den Fallstricken von GOTO ziemlich vertraut.
Vor allem Da Notepad nicht wirklich eine IDE ist die auf Syntax oder Kontext prüft.
Nur bin ich meist mit meinem Script schon am Arbeiten wenn die Programmierer in ihrer IDE ein Projekt eröffnet haben und anfangen wollen loszucoden.
Also Analysier mal Deinen Code auf Papier, da wird vermutlich rauskommen das Deine Sprünge die Grenzen von Funktionsblöcken verletzen und deshalb Variablen nicht die richtigen Werte bekommen.
Falls nicht ein Syntaxfehler vorliegt den die IDE nicht als solchen erkennt.
Wie bei Vergleich und Zuweisung. Beides an sich syntaktisch richtig aber im Kontext eines Vergleichs ist die Syntax einer Zuweisung halt falsch.
Geändert von i_make_it (19.09.2016 um 06:58 Uhr)
Ich programmiere schon seit über 35 Jahren und habe schon genug solcher Programme gesehen. Nach dem ersten Blick auf den Code in dem zitierten Thread und war damals schon klar, dass es zu einem Thread wie diesem kommen würde.
Du redest davon, tust es aber nicht. Das Konzept in C um Programme zu Strukturieren sind Funktionen nicht gotos.
Statt wie bei dir
ist die Sprache eigentlich so gedachtCode:switch(irgendwas) { case 0: Mx =42; goto Mblub; break; // ... Mblub: // code ... goto Mbob; // anderes Zeug Mbob: // nochmehr Code goto Nochweiter;
und nicht kilometerlanger Bandwurmcode in dem mit goto rumgehüpft wird.Code:void blub(int paran) { // Der Code hinter dem einen Label } void bob() { // Der Code beim anderen } // ... switch(irgendwas) { case 0: blub(42); bob(); break; // ...
Dann hätten einmal mehr Leute überhaupt Lust sich das anzusehen und man kann jede Funktion mit Ausgaben versehen.
Eventuell auch mit zusätzlichen Parametern, die nur dazu dienen in der Ausgabe anzuzeigen, woher der Aufruf kam.
Also in der Art
und bei der VerwendungCode:void foo(int caller, int arg) { Serial.print("Aufruf von"); Serial.print(caller); Serial.print(" mit "); Serial.println(arg); }
Code:// Eine Stelle foo(1, M42); // woanders foo(2, M42);
Hallo,
während der Fehlersuche frage ich mich, wie ein Serial.Print-Befehl im Programm verarbeitet wird.
Bleibt das Programm an dieser Stelle stehen, bis z.B. eine Quittung über den erfolgreichen Sendevorgang vorliegt oder wird der Befehl nur initiiert und das Programm setzt die Abarbeitung der folgenden Befehle unverzüglich fort.
Wie ist das bei 4 -5 Serial.print's direkt hintereinander? Kann zwischen den einzelnen Serial.print's noch eine Programmabarbeitung erfolgen, so dass die auf dem Monitor angezeigten Werte nicht exakt den selben Programmzustand zeigen?
Nur zur Info: ich habe " Serial.begin (250.000);" eingestellt.
vG
fredyxx
Hallo fredyxx,
Grundsätzlich benötigt die Ausgabe von Debug-Informationen etwas Zeit.
Mit und ohne ist das Timing auf alle Fälle unterschiedlich!
Zu deinem Grundproblem:
Bevor noch irgendeine Zeile C ausgeführt wird, werden die globalen Variablen initialisiert. Die meisten bekommen den Wert 0
int i;
Bei
int j = 3;
Wird der entsprechende Wert (hier 3) zugewiesen.
Dies wird aber nur nach einem Reset durchgeführt.
Andernfalls haben dein globalen Variablen den letzten vom Programm zugewiesenen Wert.
Wenn ich dein Programm noch richtig im Kopf habe hast du Hilfsvariablen in der Form
Motor_fertig = TRUE;
Womit du weiterschaltest.
Bei einem zweiten Aufruf bleiben diese auf TRUE, wenn du sie nicht extra zurück setzt.
Dann rasselt halt alles durch.
MfG Peter(TOO)
Manchmal frage ich mich, wieso meine Generation Geräte ohne Simulation entwickeln konnte?
ok, aber kann man sicher sein, dass aufeinder folgende Serial.Print's auch direkt nacheinander gesendet werden und das Programm auch dann erst weiter geht?
Alle Achtung! Das hast du noch genau richtig im Kopf. Deshalb setze ich in der LOOP mit dem STOP-Schalter auch alle Mx-fertig's auf false und erst wenn ich den wieder umschalte, kann das Justierprogramm wieder beginnen. Bei M1 ist das auch so, aber direkt danach sind alle Mx-fertig's auf true!!!???????????????????Wenn ich dein Programm noch richtig im Kopf habe hast du Hilfsvariablen in der Form
Motor_fertig = TRUE;
Womit du weiterschaltest.
vG
fredyx
Hallo,
Ganz allgemein erfolgt bei Arduiono kein Test auf erfolgreichen Sendevorgang. Wenn keiner empfängt sind die Daten halt weg.
Ob das print wartet, hängt vom Arduino Modell ab:
Bei den meisten Modellen gehen die Daten über UART vom Hauptcontroller zum USB-Controller auf dem Board. Das ist entweder ein zweiter Controller (meist ein 16U2) oder nur ein seriell zu USB Wandler (FTDI, CH340, ...). Das Print muss in diesem Falle warten, bis die Daten aus dem UART raus sind.
Dieser Vorgang kann durch einen Interrupt unterbrochen werden, z.B. wenn ein Library verwendet wird, die damit arbeitet. Was hinter dem print steht, kommt aber erst dran, wenn das print fertig ist.
Bei Arduinos mit Controllern, die selbst einen USB-Anschluss haben (Leonardo, Micro, Due, Teensy, ...), ist ein print meist nur ein sehr schneller Kopiervorgang, um den Rest kümmert sich die USB-Hardware im Chip.
switch/case ist nichts anderes als ein goto.
Die case (irgendwas) sind nichts anderes als Sprungmarken für gotos, daher müssen es in C immer auch Integer-Konstanten sein (und keine Floats oder logische Ausdrücke).
So ungern hier also manche das goto in C-Programmen sehen: es ist nur persönliches Ästhetikempfinden, nicht mehr und nicht weniger
an fredyxx:
wenn du sicher bist, dass deine Sprünge im richtigen Moment an die richtige Stelle führen, ist das kein Grund, sie durch switch/case Anweisungen zu ersetzen.
Allerdings müssen sie beide in jedem Falle immer im richtigen Moment an die richtige Stelle führen.
Bist du also sicher, dass sie stimmen, lass sie drinnen - und such den Fehler woanders.
Goto Anweisungen innerhalb von switch/case ist allerdings reichlich doppelt gemoppelt und wirklich extrem unschöner Programmierstil.
zum Debuggen mit serial:
Du kannst Wartepunkte einfügen, indem du in dein Programm ein Warten auf einen Buttondruck und wieder loslassen einfügst:
Code:#define testpin 13 // or whateverCode:while(!testpin); Serial.print(irgendwas); while(testpin);
Geändert von HaWe (16.09.2016 um 14:03 Uhr)
Lesezeichen