mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik interrupt mit watchdog


Autor: Amir B-a (sticky)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hallo.
ich verwende eine ATMeag168 (gcc).
dieser hat einen watchdog, der bei bedarf vorher einen interrupt 
auslöst.
ich wollte diesen nun nutzten um vor einen reset zustände am portpins 
abzuspeichern und beim hochfahren die abgespeicherten pins wieder mit 
den werten zu setzten, die ich zuvor abgespeichert habe.

nun meine fragen.

1. wohin muss ich die abspeichern (die pins)? also ins EEPROM oder 
woanders?

2. wie kann ich die in der ISR abgespeichrten pins global lesbar machen?
bzw kann ich eine variable die ausserhalb der isr definiert wurde auch 
innerhalb der isr manipulieren?

danke gruß sticky

Autor: Michael L. (-mic-)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hallo.

> 1. wohin muss ich die abspeichern (die pins)? also ins EEPROM oder
> woanders?

in irgendeinen nichtflüchtigen speicher. eeprom hört sich schon mal ganz 
gut an. dieser sollte natürlich schneller speichern können als der reset 
auftritt ;-)

> 2. wie kann ich die in der ISR abgespeichrten pins global lesbar machen?
> bzw kann ich eine variable die ausserhalb der isr definiert wurde auch
> innerhalb der isr manipulieren?

wenn die variable global definiert ist, kannst du sie jederzeit überall 
manipulieren.
global ist sie dann, wenn sie außerhalb einer funktion definiert ist. 
oder innerhalb einer datei ohne "static".
evtl. mußt du sie in der datei, die deine ISR enthält, mit "extern" 
deklarieren.

gruß

michael

Autor: Amir B-a (sticky)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>> 2. wie kann ich die in der ISR abgespeichrten pins global lesbar machen?
>> bzw kann ich eine variable die ausserhalb der isr definiert wurde auch
>> innerhalb der isr manipulieren?
>
> wenn die variable global definiert ist, kannst du sie jederzeit überall
> manipulieren.
> global ist sie dann, wenn sie außerhalb einer funktion definiert ist.
> oder innerhalb einer datei ohne "static".
> evtl. mußt du sie in der datei, die deine ISR enthält, mit "extern"
> deklarieren.


Ich erhalte folgende fehlermeldung wenn ich meine variable in main und 
nicht in der ISR definiere (siehe Anhang)

also der code sieht ungefähr so aus:
main(){
uint8_t (x);
}

ISR(interrupt)
{
  if (x==1){
  ...
  }
}

doch der Compiler meckert. auch extern hat hierbei nicht geholfen.

Was kann ich machen bzw was muss ich machen

Autor: Amir B-a (sticky)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
hab den anhang vergessen hier ist er

Autor: Route_66 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du hast scheinbar den Sinn eines Watchdog nicht verstanden? Dieser 
Bestandteil einer Überwachungslogik soll den ordnungsgemässen 
Programmlauf beobachten (watching). Wenn sich also die Software durch 
(eigene) Programmierfehler oder externe (EMV) Einflüsse in die Wüste 
verabschiedet ist es Unsinn, den gegenwärtigen Portzustand zu speichern 
um ihn später wieder herzustellen. Der Zustand kann nämlich Unsinn sein 
wenn der Wachhund zubeisst!
Bei Brown-Out kann das etwas anders sein. Aus leidvoller Erfahrung kann 
ich da nur zu Besonnenheit raten! Je nachdem wie schnell z.B. die 
Spannung ausfällt schafft man es, aktuelle Werte vollständig zu 
speichern - oder auch nur partiell. Und darin liegt die Gefahr! Beim 
erneuten Starten ist es sehr schwer, den vorgefundenen gespeicherten 
Daten genügend Vertrauen engegenzubringen, diese einfach auf die Ports 
zu schreiben. O.K. hängt natürlich alles vom Anwendungsfall ab, welches 
Risiko akzeptabel ist.

Autor: Amir B-a (sticky)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
der Watchdog des Atmega168 besitzt genau aus den grund überhaupt einen 
interrupt. (siehe Daten Blatt) die Port die ich abspeicher sind 
unkritisch.

Aber wenn du schon antwortes hättest du mir auch einfach eine antwort 
auf meine frage geben können.

Danke Trotzdem.

kann mir jemand trotzdem eine antwort geben ?

Autor: Justus Skorps (jussa)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
versuch es mal so:
volatile uint8_t x
ISR(interrupt)
{
   if (x==1){
   ...
   }
}
main(){
}

wobei ich auch nicht verstehe, wie du mit dem Watchdog einen Reset 
erkennen willst..laut Datenblatt kann durch den Watchdog ein Reset 
und/oder ein Interrupt ausgelöst werde...

Autor: Michael L. (-mic-)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> main(){
> uint8_t (x);
> }
>
> ISR(interrupt)
> {
>   if (x==1){
>   ...
>   }
> }
> [/c]
>
> doch der Compiler meckert. auch extern hat hierbei nicht geholfen.

wie gesagt: eien variable ist global, wenn sie AUSSERhalb einer funktion 
definiert wurde (bei bedarf könnte sie dann an anderer stelle (d.h. in 
anderen dateien) als extern deklariert werden).

bei dir ist sie INNERhalb der funktion main() definiert und damit 
unbekannt in der ISR.
deshalb nützt dir ein extern in dem fall nix.

gruß

michael

Autor: Route_66 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das ist ungefähr so sinnlos, wie wenn du bei deinem PC - der sich 
aufgehängt hat - den Reset Knopf drückst, dabei den Zustand des PCs 
speicherst, um in nach dem Hochfahren wieder in diesen zu versetzen.
Der Watchdog Reset/Interrupt ist nur dazu da, dem Programmierer eine 
Erkennungsmöglichkeit darüber zu geben, aus welchem Grund der Controller 
neu startet.
Was Du hier ständig meinst ist Folgendes (um beim Vergleich mit dem PC 
zu bleiben): wenn bei Netzausfall eine UPS die Spannungsversorgung 
übernimmt, kann sie mitteilen "Netz ist weg". Daraufhin hat der PC 
genügend Zeit, geordnet runterzufahren und wichtige Daten zu speichern. 
Bei einem Watchdog bestehen - wenn er auslöst - völlig undefinierte 
Zustände im Prozessor. Und zwar in allen Teilen. Diesen Müll 
abzuspeichern wäre schade um die Arbeit.

Autor: Amir B-a (sticky)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Justus Skorps wrote:

>laut Datenblatt kann durch den Watchdog ein Reset
> und/oder ein Interrupt ausgelöst werde...

du sagst es doch selber interrupt und reset. wobei zuerst die ISR 
ausgeführt wird.

@micha.

danke das wollte ich wissen.

@rout66

wie gesagt, das was ich abspeichere ist absolut unkritisch aber zwingend 
notwendig.
trotzdem danke  :)

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> wie gesagt, das was ich abspeichere ist absolut unkritisch aber zwingend
> notwendig.
Kann ich auch kaum glauben, wichtiger ist den Fehler zu finden warum der 
Watchdog überhaupt gebraucht wird.

Autor: Justus Skorps (jussa)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Amir B-a wrote:
> Justus Skorps wrote:
>
>
> du sagst es doch selber interrupt und reset. wobei zuerst die ISR
> ausgeführt wird.
>

du hast aber in deinem ersten Post geschrieben, dass du mit dem Watchdog 
die Werte speichern willst, bevor ein Reset auftritt...da war kein Wort 
davon, dass du nur von einem Reset sprichst, der vom Watchdog selbst 
ausgelöst wird...und bei einem "normalen" Reset durch den Resetpin oder 
weil die Spannung einbricht bringt dir der Watchdog nichts...

Autor: Amir B-a (sticky)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter wrote:

> Kann ich auch kaum glauben, wichtiger ist den Fehler zu finden warum der
> Watchdog überhaupt gebraucht wird.

weil ihr so darauf rumreitet. hier die erklärung.

ich nutze den Watchdog gezielt um einen reset softwaremäßig von einem 
Master modul auf meinem slave modul auszulösen. dabei sollen aber die am 
atmega angeschlossenen relais unbeachtet bleiebn also ihre position (ein 
oder aus geschlatet) nicht mit "geresetet" werden.

darüber hinaus verwende ich den watchdog im reset modus um das programm 
zu überwachen, wie man es vom Watchdog gewphnt ist.

Autor: Amir B-a (sticky)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Skorps

du hast recht. habe ich nicht erwähnt.

es handekt sich beim watchdog des atmega um einen enhaced watchdog der 
in 3 verschieden modi betrieben werden kann.

1 reset(statndad)
2. interrupt modus
3 interrupt-reset modus

Autor: Amir B-a (sticky)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
auszug aus dem datenblatt
 The third
mode, Interrupt and System Reset mode, combines the other two modes by 
first giving an interrupt and then switch to System Reset mode. This 
mode will for instance allow a safe shutdown
by saving critical parameters before a system reset.

Autor: Justus Skorps (jussa)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Amir B-a wrote:
> es handekt sich beim watchdog des atmega um einen enhaced watchdog der
> in 3 verschieden modi betrieben werden kann.
>
> 1 reset(statndad)
> 2. interrupt modus
> 3 interrupt-reset modus

Das ist mir schon bekannt, aber

> by saving critical parameters before a system reset.

bezieht sich eben nur auf einen durch den Watchdog ausgelösten 
Reset...und dass es dir nur darum ging, war eben nicht klar...

Autor: Amir B-a (sticky)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Skorps

du hast recht es war anfangs nicht ganz eindeutig.

Ich habe jedoch noch ein weiteres problem.

ich komme nicht in die ISR. ein reset wird zwar ausgeführt aber das 
voran gehende Interrupt wird nicht ausgelöst.

habe den WD folgendermaßen konfiguriert.
#define WDTO_16MS  0
#define WDTO_32MS  1
#define WDTO_64MS  2
#define WDTO_125MS 3
#define WDTO_250MS 4
#define WDTO_500MS 5
#define WDTO_1S    6
#define WDTO_2S    7

uint8_t Relais_Position=0;

WD_Enable(uint8_t timeout){
WDTCSR |= (1<<WDIE) | (1<<WDE);
WDTCSR |= timeout;
}

int main(){
while(1){
sei();
WD_Enable(WDTO_16MS);

ADC_Val     = Read_ADC(0); // hier soll der WD zuschlage (tut er auch)
}
return 0;
}
}

ISR (WDT_vect){ //wird leider nicht abgearbeitet
/*Abspeichern der Relaisposition vor einem Reset.*/ 
Relais_Position = PORTB;    
}


Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die Fuses müssen richtig konfiguriert sein. Zudem ist im Startup darauf 
zu achten, MCUSR zu resetten, damit der WDT funzt wie angedacht.

Einfacher als in einer WDT-ISR kannst du den Port-Wert beim Setzen des 
Ports in einer Variablen speichern, die in der .noinit-Section liegt. 
Abhängig vom Reset-Grund (MCUSR) weiß man, ob der Wert darin gültig ist, 
oder ob er initialisiert werden muss.

Eine WDT-IRQ hat zudem den Nachteil, daß sie vom I-Flag maskiert wird. 
D.h. wenn irgendwo in einer Anwendung I=0 ist (ADC-ISR?) und der WDT 
anschlägt, wird die WDT-IRQ nicht getriggert und es erfolgt direkt ein 
Reset. In deinem Soft-Reset ist es auch sinnvoll, IRQs zu deaktivieren: 
während auf den WDT gewartet wird , will man nicht durch eine andere ISR 
gestört werden... Etwas verquer das alles...

Ebenso könnte der Port-Wert also vor dem Aufruf des Soft-Reset 
gespeichert werden. (wieder in .noinit).

Johann

Autor: Amir B-a (sticky)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Johann L. wrote:
> Die Fuses müssen richtig konfiguriert sein.

sind sie!


> Zudem ist im Startup daraufzu achten, MCUSR zu resetten, damit der WDT >funzt 
wie angedacht.

habe ich jetzt gemacht aber hilft nicht. (siehe code)

> Einfacher als in einer WDT-ISR kannst du den Port-Wert beim Setzen des
> Ports in einer Variablen speichern, die in der *.noinit-Section* liegt.
> Abhängig vom Reset-Grund (MCUSR) weiß man, ob der Wert darin gültig ist,
> oder ob er initialisiert werden muss.

das versteh ich leider nicht ganz. und was ist die noint-sektion?

> Eine WDT-IRQ hat zudem den Nachteil, daß sie vom I-Flag maskiert wird.
> D.h. wenn irgendwo in einer Anwendung I=0 ist (ADC-ISR?) und der WDT
> anschlägt, wird die WDT-IRQ nicht getriggert und es erfolgt direkt ein
> Reset.

das ist mir klar. danke für den hinweis. dort wo ich interrupts nicht 
erlaube ist auch der WDT deaktiviert.

>In deinem Soft-Reset ist es auch sinnvoll, IRQs zu deaktivieren:
> während auf den WDT gewartet wird , will man nicht durch eine andere ISR
> gestört werden... Etwas verquer das alles...

ich dachte innerhalb einer ISR sind interrupt eh deaktiviert.

> Ebenso könnte der Port-Wert also vor dem Aufruf des Soft-Reset
> gespeichert werden. (wieder in .noinit).

wieder nicht verstanden
#define WDTO_16MS  0
#define WDTO_32MS  1
#define WDTO_64MS  2
#define WDTO_125MS 3
#define WDTO_250MS 4
#define WDTO_500MS 5
#define WDTO_1S    6
#define WDTO_2S    7

uint8_t Relais_Position=0;

WD_Enable(uint8_t timeout){
MCUSR &= ~(1<<WDRF);
WDTCSR |= (1<<WDIE) | (1<<WDE);
WDTCSR |= timeout;
}

int main(){
while(1){
sei();
WD_Enable(WDTO_16MS);

ADC_Val     = Read_ADC(0); // hier soll der WD zuschlage (tut er auch)
}
return 0;
}
}

ISR (WDT_vect){ //wird leider nicht abgearbeitet
/*Abspeichern der Relaisposition vor einem Reset.*/ 
Relais_Position = PORTB;    
}

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die einzig sinnvolle Anwendung des Watchdoginterrupt ist, den 
Stackpointer und nen RAM-Dump auszugeben, um nacher zu sehen, wo das 
Programm gehangen hat.

Wenn man nen Timerinterrupt braucht, nimmt man einfach nen Timer.
Ansonsten kann es passieren, daß Watchdogfunktion und Timerfunktion sich 
gegenseitig behindern.


Es gibt keinen vernünftigen Grund, aus ner funktionierenden Anwendung 
heraus einen Reset zu machen.
Wenn die Portpins erhalten bleiben sollen, machste eben ganz einfach 
keinen Reset.
Es gibt unter C genügend saubere Programmierlösungen, um an den Anfang 
des Main zurück zu kehren.


Peter

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.