Hallo,
wie dem Betreff schon zu entnehmen ist habe ich ein Problem beim
ausführen meines Programmcodes aber hier erstmal ein paar Daten worum es
sich handelt.
Mikrocontroller: Atmega328PB
Programmieradapter: AVR-Dragon
Programmierumgebung: Atmel Studio 7
Beim Programmcode handelt sich es um eine Statemachine die durch ein
Flag welches in der Mainloop geprüft wird ob es gesetzt ist aufgerufen
wird. Das Flag wird in einem Timerinterrupt alle 50ms gesetzt.
Angestoßen wird das ganze dadurch das die Variable "State" auf
"Ausfahren" gesetzt wird. Nachdem alles im case Ausfahren abgearbeitet
ist sollte es beim nächsten mal wenn die Statemachine aufgerufen wird in
den Ausgefahren case springen was aber nicht passiert. Um der ganzen
Sache auf den Grund zu gehen habe ich angefangen das ganze zu Debuggen.
Beim Debuggen habe ich festgestellt dass wenn ich einen Breakpoint im
Ausfahren case erstelle das Programm beim nächsten mal aufrufen der
Statemachine in den Ausgefahren case springt. Ohne Breakpoint wird der
Programmcode dann wieder nicht richtig ausgeführt egal ob im Debugmodus
oder normal Programmiert. Woran könnte das liegen ?
Mit freundlichen Grüßen.
Lukas W.
Lukas W. schrieb:> Ohne Breakpoint wird der> Programmcode dann wieder nicht richtig ausgeführt egal ob im Debugmodus> oder normal Programmiert. Woran könnte das liegen ?
"Wilde Sprünge" deuten erst mal auf einen vom Compiler optimierten
Code hin den man grundsätzlich nicht richtig debuggen kann.
YMMV
Auch in der Make-Version "Debug" kann der Compiler zum Optimieren
aufgerufen worden sein. Prüfe daher erst ob dein Build ohne
Compiler-Optimierung eingestellt wurde.
Lukas W. schrieb:> ... Das Flag wird in einem Timerinterrupt alle 50ms gesetzt.
Beim Flag fehlt "volatile"?
> case Warten:> break;
Das kannst du streichen.
leo
Danke schon mal für die Antworten das ausschalten der Codeoptimierung
hat leider nichts gebracht (Projekteinstellungen->Toolchain->AVR/GNU C
Compiler->Optimization und Optimization Level auf None(-Q0)). Die
Variable "State" hatte ich schon als Volatile deklariert.
Hallo,
stell dir bitte einmal die Frage was jemand Fremdes mit dem switch-case
Code alleine anfangen kann? Kürze das Programm soweit zusammen wie es
möglich ist und zeige es uns. Dann erst kann das Forum helfen.
Lukas W. schrieb:> Das Flag wird in einem Timerinterrupt alle 50ms gesetzt.
Schafft es denn der Motor in 50 ms auszufahren (d.h. den Zustand Warten
zu erreichen)?
Lukas W. schrieb:> Ohne Breakpoint wird der Programmcode dann wieder> nicht richtig ausgeführt egal ob im Debugmodus> oder normal Programmiert. Woran könnte das liegen ?
Daran, dass Dein (Denk-)Modell nicht stimmt.
Die Zustände der Mechanik und die Zustände des steuernden
Automaten sind erstmal nicht identisch: Wenn die Mechanik
betriebsmäßig ZWEI Zustände kennt, z.B. "Eingefahren" und
"Ausgefahren", muss der steuernde Automat VIER Zustände
kennen: "Eingefahren", "Ausfahren", "Ausgefahren" und
"Einfahren". Das liegt einfach daran, dass der steuernde
Automat wesentlich schneller ist als die gesteuerte
Mechanik, so dass "Übergänge" der Mechanik in "Zustände"
des steuernden Automaten abgebildet werden müssen.
Die nächste Falle lauert schon: Mit vier Endlagenschaltern
können zwar vier verschiedene Zustände codiert werden --
von diesen sind aber nur drei betriebsmäßig zulässig:
- "00" = "Aktor in Bewegung",
- "10" = "vordere Endlage",
- "01" = "hintere Endlage",
- "11" = unzulässig (--> Fehler).
Man braucht also zur korrekten Behandlung erstens einen
Timeout und muss zweitens die Vorgeschichte berücksichtigen,
um softwaremäßig "Einfahren" und "Ausfahren" unterscheiden
zu können.
Ungefähr darauf wollte Dirk wohl mit seiner kurzen Frage
hinweisen, nehme ich an.
Egon D. schrieb:> Ungefähr darauf wollte Dirk wohl mit seiner kurzen Frage> hinweisen, nehme ich an.
Ich wollte darauf hinaus, dass da sowas wie
[c]
if (Taste_gedrueckt())
State = Ausfahren;
else
State = Warten;
[\c]
in der ISR steht
Dirk B. schrieb:> Egon D. schrieb:>> Ungefähr darauf wollte Dirk wohl mit seiner kurzen Frage>> hinweisen, nehme ich an.>> Ich wollte darauf hinaus, dass da sowas wie>
1
if(Taste_gedrueckt())
2
State=Ausfahren;
3
else
4
State=Warten;
>> in der ISR steht
Als "non-Windows" geht es besser ;-)
Sprich [/c] statt [\c] am Ende
Dirk B. schrieb:> Carl D. schrieb:>> Als "non-Windows" geht es besser ;-)>>>> Sprich [/c] statt [\c] am Ende>> ?♂️ Auf der Tablet-Tastatur ist der \ direkt neben [
Auf meiner auch, dann drücke ich vorher auf die Taste "123" und schon
paßt's ;-)
Carl D. schrieb:> Dirk B. schrieb:>> Carl D. schrieb:>>> Als "non-Windows" geht es besser ;-)>>>>>> Sprich [/c] statt [\c] am Ende>>>> ?♂️ Auf der Tablet-Tastatur ist der \ direkt neben [>> Auf meiner auch, dann drücke ich vorher auf die Taste "123" und schon> paßt's ;-)
Ja, ich demnächst auch.
Danke für die Antworten. Die Statemachine war schonmal weiter ausgebaut
ich wollte die Statemachine zum finden des Fehlers nur so klein wie
möglich halten damit das ganze übersichtlicher ist und es selbst so
schon nicht funktioniert. Der Motor braucht länger als 50ms zum
Ausfahren bzw bis er den Hallsensor erreicht, was kein Problem
darstellen sollte da die Statemachine solange immer wieder in den
Ausgefahren case springen sollte und prüfen sollte ob der Motor am
Hallsensor angekommen ist. Der Motor ist auch nicht schnell genug um dem
Hallsensor in 50ms überfahren zu können. Hier nochmal etwas mehr code
ich hoffe das macht das ganze verständlicher. resetSerCommand() am ende
setzt das Serielle Komando zurück was verhindert das befehle doppelt
ausgeführt werden.
Lukas W. schrieb:> if(getTimeSliceFlag() == 1)
Sicher dass das Flag auch dort wieder gelöscht wird?!
Lukas W. schrieb:> resetSerCommand() am ende> setzt das Serielle Komando zurück was verhindert das befehle doppelt> ausgeführt werden.
Das ist Mist (die wahrscheinliche Fehlerquelle). Bau das in die
Statemachine ein! (Setzt das doch sicher eh nur auf "case 4:"!?
So wie ich das sehe, sollte das zweite Switch außerhalb der If Bedingung
liegen. Also ständig ausgeführt werden....
Bzw. ich würde die Main, also die Switch Blöcke ungebremst laufen lassen
und nur die Sensor/etc.-Abfrage, in den 50ms Task-Slot (IF-Block
außerhalb der Switches) legen.
Teo D. schrieb:> Lukas W. schrieb:>> if(getTimeSliceFlag() == 1)>> Sicher dass das Flag auch dort wieder gelöscht wird?!
Zwei zeilen darunter wird es gelöscht. Das Timing habe ich mit einem
Oszi gemessen indem ich einen Ausgang toggeln lassen habe.
> Das ist Mist (die wahrscheinliche Fehlerquelle). Bau das in die> Statemachine ein! (Setzt das doch sicher eh nur auf "case 4:"!?
Was soll case 4: mit meinem Problem zutun haben case 4: wird nur
aufgerufen wenn ich befehl 4 per seriellen Komando ausführen will
Lukas W. schrieb:>> Das ist Mist (die wahrscheinliche Fehlerquelle). Bau das in die>> Statemachine ein! (Setzt das doch sicher eh nur auf "case 4:"!?> Was soll case 4: mit meinem Problem zutun haben case 4: wird nur> aufgerufen wenn ich befehl 4 per seriellen Komando ausführen willLukas W. schrieb:> resetSerCommand() am ende> setzt das Serielle Komando zurück was verhindert das befehle doppelt> ausgeführt werden.
Wie funst das den dann, bzw. was wird den anstelle ausgefürt?
Ich schicke den Befehl 3 (case 3: des ersten Switch) per serielle
Schnittstelle was soweit funktionert. In dem case 3 des ersten Switch
wird der State der Statemachine gleich Ausfahren gesetzt was den Motor
Startet und den State auf Ausgefahren setzt. Der Motor dreht sich aber
die Statemachine kommt beim nächsten mal ausführen der Statemachine
nicht in den Ausgefahren State wo es den Motor stoppen sollte wenn er
den Hallschalter erreicht sondern springt in den Warten state was
eigentlich nicht passieren darf solange der Motor nicht am Hallsensor
angekommen ist.
Lukas W. schrieb:> Ich schicke den Befehl 3
Zu viel Blabla, zu wenig Code. Mach ein minimales und vollstaendiges
Beispiel, das den Fehler wiedergibt.
leo
Also nach Stundenlangen Kopfzerbrechen habe ich den Fehler jetzt
gefunden. Der Fehler lag nicht in der Software sondern in der Hardware.
Das Labornetzteil das ich verwende konnte den hohen Anlaufstrom des
Motors nicht bewältigen was zur folge hatte das die Versorgungsspannung
etwas auf der Mikrocontroller Seite zusammengebrochen ist und dieser das
Programm dann anscheinend von neuem gestartet hat oder irgend einen
anderen mist gemacht hat. Vielen dank an alle die versucht haben mir bei
meinem Problem zu helfen.
Mit freundlichen Grüßen.
Lukas W.
Lukas W. schrieb:> Also nach Stundenlangen Kopfzerbrechen habe ich den Fehler jetzt> gefunden. Der Fehler lag nicht in der Software sondern in der Hardware.> Das Labornetzteil das ich verwende konnte den hohen Anlaufstrom des> Motors nicht bewältigen was zur folge hatte das die Versorgungsspannung> etwas auf der Mikrocontroller Seite zusammengebrochen ist und dieser das> Programm dann anscheinend von neuem gestartet hat
Selbst wenn das wirklich so gewesen wäre, hätte ein gutes Programm
auch dann (also nach einem unerwarteten Reset mit kompletten
Informationsverlust) noch keinen völligen Mist gemacht...
Für sowas sieht man natürlich einen initialen "Unknown"-Status vor, wenn
es keine beschaffbare Information über eine bestehende Aktivität des
Aktors gibt. Den braucht man sowieso, denn mindestens beim allerersten
Start des Programms kann diese Situation eintreten, wenn der Aktor
(warum auch immer) schon was tut.
Der Status endet, wenn entweder einer der Endlagensensoren was meldet
oder eine Maximalzeit vergangen ist (die für den vollen Weg nötige +
etliche % Sicherheit). Dann wechselt man entweder nach in einen der
beiden Endlagen-Stati (wenn halt der entsprechende Sensor sich gemeldet
hat) oder nach "kaputt". Denn das kann nur bedeuten, dass der Aktor
einen erteilten Befehl nicht bis zum Ende ausführen konnte oder halt en
Sensor defekt ist. In jedem Fall: kaputt.
Sprich: die hast noch viel zu lernen...