Hi
Ich habe ein Problem mit meinem Programm, genauer gesagt mit der delay
Funktion. Ich will bsp. ein Delay von 100ms.
Also include ich delay.h und habe eine Routine geschrieben
void mydelayms (int ms)
{
while ( ms-- != 0)
{
_delay_ms(1);
asm("wdr");
}
}
Aufrufen tu ich sie z.b. mit mydelayms(100);
Aber jedesmal wenn die Routine aufgerufen wird ist ms = 0, und die
while-Schleife wird zur Endlosschleife.
Wenn ich das delay direkt in der void main aufrufe, also z.B.
_delay_ms(1),
resettet das Programm und das Watchdog Resetflag in MCUSR wird 1.
Meinen Watchdog initialisiere ich mit
WDTCSR = (1<<WDCE) | (1<<WDE);
ich habe aber auch mit WDP3 = 1 probiert, genau dasselbe :-/
Ich weiss dass die delay_ms nur auf 212/ CPU-Frequenz gesetzt werden
darf, aber bei einem 12MHz Quarz sollten ja 10ms trotzdem drin sein.
Also ist das erste Problem dass meine integer nicht in der Delayroutine
übernommen wird und selbst wenn sie es würde, würde mein _delay_ms den
watchdog auslösen.
Bin echt am verzweifeln.
Ich habe es jetzt zwar nicht probiert, aber ich bezweifle stark, dass
"while ( ms-- != 0)" das tut was du dir davon erhoffst. Du kannst bei
einem Vergleich nicht zeitgleich die Variable verändern. Das das dann in
einer Endlosschleife endet und der Watchdog auslöst ist klar. Du musst
"while ( ms != 0)" schreiben und in der Schleife dann "ms--;".
Ganz abgesehen davon solltest du bei dem Vergleich eher ms > 0
schreiben, um Fehlerfälle auszuschließen. Was ist zum Beispiel, wenn
jemand die Routine mit einem negativen Wert aufruft? Das mit != geht
zwar, ist aber kein guter Programmierstil.
lg
ISP
Morgy schrieb:> Aufrufen tu ich sie z.b. mit mydelayms(100);> Aber jedesmal wenn die Routine aufgerufen wird ist ms = 0, und die> while-Schleife wird zur Endlosschleife.
Dein Delay funktioniert. Das Problem muss woanders liegen.
Mach mal ein Progrämmchen in dem einfach nur eine LED mit dem Delay
blinkt. Erstmal ohne WDT dann mit. Und benutz die Funktionen aus der
Bibliothek.
IS P. schrieb:> ist aber kein guter Programmierstil.
Mit deinen Kenntnissen solltest du dich zu Stilfragen lieber nicht
äussern.
mfg.
Thomas Eckmann schrieb:> IS P. schrieb:>> ist aber kein guter Programmierstil.>> Mit deinen Kenntnissen solltest du dich zu Stilfragen lieber nicht> äussern.
Ich habe gesagt, dass ich es nicht getestet habe. Mir war nicht bekannt,
dass man bei Vergleichen Variablen neue Werte geben kann (bei C
zumindest nicht). Macht den Quelltext auch nicht gerade übersichtlicher.
Das sagt über meinen Kenntnisstand nichts aus. Ich weiß nicht was du
hier heraus nimmst und über um über meine Kenntnisse zu mutmaßen. Das
die Funktion mit "!=" zu programmieren ist Schwachsinn, da wie schon
gesagt, das Ganze endlos läuft, wenn ms negativ ist. Solltest du das
anders sehen, möchte hier viel eher deine Kenntnisse anzweifeln.
lg
ISP
PS: falls du das ganze darauf beziehst, dass der Watchdog bei jedem
Schleifendurchlauf zurückgesetzt wird: so weit habe ich mir das ganze
vorhin nicht angeguckt, da ich nach dem "ms--" der Meinung war, dass es
so nicht gehen kann.
IS P. schrieb:> Das> die Funktion mit "!=" zu programmieren ist Schwachsinn, da wie schon> gesagt, das Ganze endlos läuft, wenn ms negativ ist. Solltest du das> anders sehen, möchte hier viel eher deine Kenntnisse anzweifeln.
Das sehe ich anders. Und jeder andere C-Programmierer auch.
mfg.
IS P. schrieb:> Dann nenne mir hierfür bitte einen Grund.
Dafür, dass du keine Ahnung hast? Weiss ich nicht.
Aber mal eine kleine Rechenaufgabe:
Was ist -32768 - 1?
mfg.
Okay, du willst also darauf hinaus, das ganze irgendwann unweigerlich
bei 0 ankommt? Das mag sein, aber dann macht die Routine nicht das, was
sie eigentlich soll. Es wäre wohl wesentlich sinnvoller, bei einem
negativen Wert die Schleife erst gar nicht durchlaufen zu lassen. Könnte
man negativ Zeit abwarten, hätte Morgy eine Zeitmaschine erfunden. Mir
geht es hier nicht darum ob es so vielleicht auch irgendwie geht,
sondern, dass es anders schlichtweg sinnvoller ist. Wenn du das anders
sieht schön, das ist noch lange kein Grund mir hier zu erzählen ich
hätte keine Ahnung. Falls es dir aufgefallen ist bist du derjenige, der
mich angegriffen hat. Du solltest dich mit deinen Äußerungen etwas
zurückhalten.
lg
ISP
IS P. schrieb:> Wenn du das anders> sieht schön, das ist noch lange kein Grund mir hier zu erzählen ich> hätte keine Ahnung. Falls es dir aufgefallen ist bist du derjenige, der> mich angegriffen hat. Du solltest dich mit deinen Äußerungen etwas> zurückhalten.
Einen Scheiss werde ich tun.
IS P. schrieb:> Ich habe es jetzt zwar nicht probiert, aber ich bezweifle stark, dass> "while ( ms-- != 0)" das tut was du dir davon erhoffst. Du kannst bei> einem Vergleich nicht zeitgleich die Variable verändern. Das das dann in> einer Endlosschleife endet und der Watchdog auslöst ist klar. Du musst> "while ( ms != 0)" schreiben und in der Schleife dann "ms--;".
Das ist schlicht und ergreifend Unsinn.
Nur weil das
1
while(!ms--)
anders aussieht als das
1
while(ms--!=0)
macht es noch lange nichts anderes.
Das einzige, was an seiner Funktion auszusetzen ist, ist dass er nicht
"unsigned int" statt "int" benutzt.
mfg.
Thomas Eckmann schrieb:> IS P. schrieb:>> Wenn du das anders>> sieht schön, das ist noch lange kein Grund mir hier zu erzählen ich>> hätte keine Ahnung. Falls es dir aufgefallen ist bist du derjenige, der>> mich angegriffen hat. Du solltest dich mit deinen Äußerungen etwas>> zurückhalten.>> Einen Scheiss werde ich tun.
Gleich ausfällig werden? Da scheint es aber jemand nötig zu haben...
> IS P. schrieb:>> Ich habe es jetzt zwar nicht probiert, aber ich bezweifle stark, dass>> "while ( ms-- != 0)" das tut was du dir davon erhoffst. Du kannst bei>> einem Vergleich nicht zeitgleich die Variable verändern.>> Das ist schlicht und ergreifend Unsinn.>> Nur weil das>
1
>while(!ms--)
2
>
>> anders aussieht als das>>
1
>while(ms--!=0)
2
>
>> macht es noch lange nichts anderes.>>> Das einzige, was an seiner Funktion auszusetzen ist, ist dass er nicht> "unsigned int" statt "int" benutzt.>> mfg.
Ich habe bereits gesagt, dass mir nicht bekannt war, dass man innerhalb
einer Bedingung Variablen dekrementieren kann. Ist ja gut wenn es so
geht. Das ändert nichts an dem, was ich im vorherigen Post geschrieben
habe.
lg
ISP
Thomas Eckmann schrieb:> Nur weil das> while(!ms--)>> anders aussieht als das> while ( ms-- != 0)>> macht es noch lange nichts anderes.
Doch... die erste Bedingung ist True wenn ms-- Falsch also null ist, die
zweite für ms-- ungleich null.
Beim Zweiten kann man sich das Prüfen auf ungleich null eigentlich auch
sparen da in C automatisch alles ungleich null true ist.
IS P. schrieb:> Du kannst bei> einem Vergleich nicht zeitgleich die Variable verändern.
Und wie man das kann, sogar auf verschiedene Arten:
Mit while(--ms) wird ms erst dekrementiert und dann geprüft, bei
while(ms--) wird zuerst dekrementiert...
IS P. schrieb:> Ich weiß nicht was du> hier heraus nimmst und über um über meine Kenntnisse zu mutmaßen.
Also ich würde das nehmen:
IS P. schrieb:> Du kannst bei> einem Vergleich nicht zeitgleich die Variable verändern.IS P. schrieb:> Mir war nicht bekannt,> dass man bei Vergleichen Variablen neue Werte geben kann
Ananas schrieb:>> Du kannst bei>> einem Vergleich nicht zeitgleich die Variable verändern.> Und wie man das kann, sogar auf verschiedene Arten:> Mit while(--ms) wird ms erst dekrementiert und dann geprüft, bei> while(ms--) wird zuerst dekrementiert...
Man kann sogar direkt Zuweisungen in Ausdrücken verwenden:
1
while((ms=ms-1)>-1)...
oder
1
while(ms=ms-1,ms>-1)...
LG, Sebastian
Morgy schrieb:> Meinen Watchdog initialisiere ich mit> WDTCSR = (1<<WDCE) | (1<<WDE);> ich habe aber auch mit WDP3 = 1 probiert, genau dasselbe :-/
Diese Zeile bewirkt nur, dass die darauffolgende Zeile die
Watchdog-Parameter ändern darf. Wie setzt du diese Parameter genau?
Hast du eventuell die Fuse WDTON gesetzt?
Und löscht du WDRF in MCUSR beim Startup so wie im Datenblatt
beschrieben?
Und geschieht das ganze innerhalb eines cli()-Bereichs?
Morgy schrieb:> Aber jedesmal wenn die Routine aufgerufen wird ist ms = 0, und die> while-Schleife wird zur Endlosschleife.
Was meinst du damit genau?
LG, Sebastian
Ein schleifendurchlauf dauert um ein vielfaches zu lange. Derart
timeinkritische sachen sollten in assembler umgesetzt werden, wo man die
instruktionen und dauer kennt. Verwende doch einfach direkt _delay_ms,
oder, falls du wirklich wärend dem warten asemblerinstruktionen einfügen
musst, nimm assembler, oder nutze zumindest das "duff's device" um
zumindest in die nähe der richtigen wartezeit zu kommen...
Das wdr ist ja ziemlicher unsinn, warum ist es da?
1
while(ms--!=0)// equivalent zu while(i--), wobei bei i=0 while(0) gilt.
2
{
3
_delay_ms(1);
4
asm("wdr");// diese assemblerinstruktion, wdr, steht für watchdog reset, und tut genau das.
@gvs
Beim Atmega328P heisst das Register wirklich WDTCSR, steht auch im
Datenblatt.
An alle anderen muss ich sagen, dass ich diesen Codeschnipsel einfach
copy-paste habe, da er mir logisch erschien und eig auch ganz gut
funktioniert, nur wie gesagt wenn ich die void aufrufe, wird die
Variable nicht übernommen, us bleibt immer null.
Und warum der Watchdog auslöst, selbst wenn er auf 512k Zyklen gesetzt
wird, ist mir auch n Rätsel.
Vergiss die DELAY Function für alles was über einige µsec hinausgeht.
Die Delay macht nichts anderes als den µC in einer Schleife mit
nichtstun zu halten.
Jeder Interrupt , zb ein externer Pin, unterbricht dieses Delay und die
Zeit wird um die Interruptdauer länger.
Die einzige sinnvolle Lösung an diese Stelle ist ein Timer der alle 100
ms einen Interrupt auslöst.
In diesem Interrupt dann den watchdogreset ausführen.
Daniel A. schrieb:> Ein schleifendurchlauf dauert um ein vielfaches zu lange.
Wie gross ist denn diess Vielfache?
Die Schleife läuft 1ms plus ein paar Takte für sich selbst. Der Watchdog
steht auf 16ms. Da dauert gar nichts zu lange.
Daniel A. schrieb:> Derart> timeinkritische sachen sollten in assembler umgesetzt werden
Die alte Mär...
Daniel A. schrieb:> Das wdr ist ja ziemlicher unsinn, warum ist es da?
Ja ja.
Die mydelayms-Funktion funktioniert. Auch mit Watchdog.
Problematisch kann es werden, wenn der WD-Reset ausgelöst wurde und sich
am Anfang des Programms aufwendige Initialisierungen befinden. Dann kann
der Watchdog auslösen, bevor man den ersten wdr gemacht hat.
Der Watchdog wird nach einem Reset nicht zurück gesetzt! Deshalb muss
das Einstellen des Watchdogs als erste Instruktion erfolgen.
Zurückgesetzt wird der Watchdog beim Start nur, wenn man die Spannung
abschaltet.
mfg.
Ralph schrieb:> Die einzige sinnvolle Lösung an diese Stelle ist ein Timer der alle 100> ms einen Interrupt auslöst. In diesem Interrupt dann den watchdogreset> ausführen.
Ich würde dann einfach den Watchdog gar nicht einschalten. Es ist
absurd, eine Hardwarekomponente (Watchdog) angetriggert durch eine
Hardwarekomponente (Timer) gesteuert durch eine Hardwarekomponente
(Interruptverwaltung) zurückzusetzen, und zu meinen, damit würde dann
die Software überwacht.
Denn das ist der eigentlich Sinn des Watchdogs: Softwareüberwachung.
Wenn die Software sich in einer Ecke festgebissen hat, dann wird der
Wachtdog nicht mehr zyklisch bedient, es kommt der Rammhammer
"Watchdogreset" und setzt das System zurück.
Wenn die Software sich in einer Ecke festgebissen hat, und der Timer
frisch, fröhlich, frei alle 100ms einen Interrupt auslöst, der dann den
Watchdog bedient, dann wurde das Zeil verfehlt...
Man schreibt eine Software so, dass die Hauptschleife zyklisch den
Watchdog zurürcksetzt. Wenn die Hauptschleife nicht mehr (schnell genug)
durchlaufen wird, dann liegt ein Ablauffehler vor und das System wird
zurückgesetzt. Beim Start wird nachgeschaut, was die Ursache für den
Reset war. Und wenn der Reset vom Watchdog kam, wird ein Fehler
ausgegeben.
Merksatz: ein delay() ist nur Verschwendung von Rechenleistung! Denn da
wartet der uC mit Vollgas, bis er weitermachen darf. Ein delay() ist
meist nicht die Lösung, sondern das Symptom oder schlimmer die Ursache
eines Problems.
Man muss sich wirklich fragen, was ein Wachhund bringen soll, den man
hinter einer schalldichten Tür einsperrt!
Also:
1. Programm ist im Nirwana.
2. Timer ist abgelaufen
3. Merke Rücksprungadresse
4. Ab in die Timerroutine
5. Fummel am Wachhund rum
6. Beende Timerroutine
7. Rücksprung POP(RETI) - (ins Nirwana)
Eine wirklich tolle Sequenz!
Ob es sinnvoll ist weiß ich nicht, fest steht aber:
>while ( ms-- != 0)
Funktioniert und ist auch legal. Man sollte aber die Reihenfolge im Auge
behalten.
Also erst Vergleichen und dann -1.
Natürlich sind die Effekte beim Aufruf mit negativer Werten bestenfalls
lustig. Früher wussten die Programmierer noch was sie tun und was sie
mit welchen Werten aufrufen (dürfen).
Es gibt natürlich noch die Möglichkeit mit unsigned zu arbeiten, aber
dann
kommt bestimmt gleich die Frage: "Was passiert beim Aufruf mit 0";-)
Lothar Miller schrieb:> Merksatz: ein delay() ist nur Verschwendung von Rechenleistung! Denn da> wartet der uC mit Vollgas, bis er weitermachen darf. Ein delay() ist> meist nicht die Lösung, sondern das Symptom oder schlimmer die Ursache> eines Problems.
Das ist zwar fast immer richtig, aber sein Programm muss trotzdem
laufen. Sonst ist was anderes faul.
mfg.
> Ganz abgesehen davon solltest du bei dem Vergleich> eher ms > 0 schreiben, um Fehlerfälle auszuschließen.> Was ist zum Beispiel, wenn jemand die Routine mit einem> negativen Wert aufruft?
Warum sollte er >0 schreiben?
Argument 1:
> Das mit != geht zwar, ist aber kein guter Programmierstil.
Über persönlichen Geschmack streiten Menschen gerne, aber es hilft
niemanden weiter.
Argument 2:
> Das die Funktion mit "!=" zu programmieren ist Schwachsinn, da wie> schon gesagt, das Ganze endlos läuft, wenn ms negativ ist.
Tut es nicht, wie bereits weiter oben erwähnt wurde.
Argument 3:
> Okay, du willst also darauf hinaus, das ganze irgendwann unweigerlich> bei 0 ankommt? Das mag sein, aber dann macht die Routine nicht das,> was sie eigentlich soll.
Was soll sie denn bei negativen Werten tun? Warte du doch mal -20
Millisekunden, ich bin gespannt, wie Du das anstellst.
Um zum Thema zurück zu kommen: Ich sehe in der delay Funktionen auch
keinen Fehler. Ist stimme Thomas zu, dass der Fehler ganz woanders
liegt.
IS P. schrieb:> Das die Funktion mit "!=" zu programmieren ist Schwachsinn
Ganz und gar nicht, denn ein '!=' kann ein AVR mit dem CPSE Befehl
direkt auswerten. Für einen '>' Vergleich braucht er mehr Befehle. Zum
Glück merkt der Compiler das und ersetzt bei einem unsigned-Wert den
'>0' Vergleich durch den CPSE Befehl.
Fazit: irgendwelche Sachen zu behaupten, von denen man nicht ausreichend
viel weiß (eine Ahnung zu haben reicht da nicht aus) das würde ich als
gewagt und irreführend bezeichnen...
Lothar Miller schrieb:> Man schreibt eine Software so, dass die Hauptschleife zyklisch den> Watchdog zurürcksetzt. Wenn die Hauptschleife nicht mehr (schnell genug)> durchlaufen wird, dann liegt ein Ablauffehler vor und das System wird> zurückgesetzt. Beim Start wird nachgeschaut, was die Ursache für den> Reset war. Und wenn der Reset vom Watchdog kam, wird ein Fehler> ausgegeben.
Das stimmt soweit schon, hab ich ja auch.
Nur will ich in meinem Programm (manche wissens vllt noch) einen
Brushlessmotor ansteuern, und beim Anlauf und beim Bremsen will ich ne
bestimmte Phase bestromen und dem Programm Zeit geben, dass der Motor in
diese Position verfährt.
Kontrollieren kann ich es ohne Hallsensor leider nicht, denn die
Rückkommutierung im Anlauf ist absoluter Mist.
Morgy schrieb:> wenn ich die void aufrufe, wird die> Variable nicht übernommen, us bleibt immer null.
Das kann eigentlich nicht sein. mydelayms() (wenn du die mit "die void"
meinst) ist nicht falsch. Der Fehler muss woanders liegen.
Morgy schrieb:
> Meinen Watchdog initialisiere ich mit> WDTCSR = (1<<WDCE) | (1<<WDE);> ich habe aber auch mit WDP3 = 1 probiert, genau dasselbe :-/> Und warum der Watchdog auslöst, selbst wenn er auf 512k Zyklen gesetzt> wird, ist mir auch n Rätsel.
Das kann eigentlich auch nicht sein. Bist du sicher, dass du den
Watchdog richtig initialisierst? Zeig mal den Quellcode dafür ab Beginn
main(), inklusive dem Löschen von WDRF in MCUSR. Und die Antwork auf die
Frage nach Fuse WDTON steht auch noch aus.
LG, Sebastian