Forum: Mikrocontroller und Digitale Elektronik Delay bringt Watchdog zum Reset


von Morgy (Gast)


Lesenswert?

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.

von Morgy (Gast)


Lesenswert?

Ach ja weiss nicht obs was dazu beiträgt aber es ist ein Atmega328P 
(Arduino) und debuggt wird mit dem AVR Dragon

von IS P. (isp)


Lesenswert?

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

von Thomas E. (thomase)


Lesenswert?

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.

von IS P. (isp)


Lesenswert?

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.

von Thomas E. (thomase)


Lesenswert?

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.

von IS P. (isp)


Lesenswert?

Dann nenne mir hierfür bitte einen Grund.

lg
ISP

von Thomas E. (thomase)


Lesenswert?

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.

von IS P. (isp)


Lesenswert?

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

von Thomas E. (thomase)


Lesenswert?

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.

von gvs (Gast)


Lesenswert?

Morgy schrieb:
> Meinen Watchdog initialisiere ich mit
>   WDTCSR = (1<<WDCE) | (1<<WDE);

oder WDTCR ?

http://www.mikrocontroller.net/articles/AVR-Tutorial:_Watchdog

Übrigens
Bringt euer geplänkel auch ne Lösung für das Problem ?

von IS P. (isp)


Lesenswert?

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

von Ananas (Gast)


Lesenswert?

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...

von Thomas E. (thomase)


Lesenswert?

Ananas schrieb:
> while(ms--)
Hast recht. Welch ein Schwachsinn. Sieht sonst irgendwie auch komisch 
aus.
Asche auf mein Haupt.

mfg.

von Ananas (Gast)


Lesenswert?

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

von Sebastian W. (wangnick)


Lesenswert?

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

von Daniel A. (daniel-a)


Lesenswert?

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.
5
  }

von Morgy (Gast)


Lesenswert?

@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.

von Ralph (Gast)


Lesenswert?

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.

von Thomas E. (thomase)


Lesenswert?

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.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

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.

von Amateur (Gast)


Lesenswert?

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";-)

von Max H. (hartl192)


Lesenswert?

Amateur schrieb:
> "Was passiert beim Aufruf mit 0"
Dann wird die schleife null Mal ausgeführt. ms-- ist null wenn ms vor 
dem Aufruf null war.

von Thomas E. (thomase)


Lesenswert?

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.

von stefanus (Gast)


Lesenswert?

> 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.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

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...

von Morgy (Gast)


Lesenswert?

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.

von Sebastian W. (wangnick)


Lesenswert?

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

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.