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
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
>> 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:
1 | main(){ |
2 | uint8_t (x); |
3 | }
|
4 | |
5 | ISR(interrupt) |
6 | {
|
7 | if (x==1){ |
8 | ...
|
9 | }
|
10 | }
|
doch der Compiler meckert. auch extern hat hierbei nicht geholfen. Was kann ich machen bzw was muss ich machen
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.
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 ?
versuch es mal so:
1 | volatile uint8_t x |
2 | ISR(interrupt) |
3 | {
|
4 | if (x==1){ |
5 | ...
|
6 | }
|
7 | }
|
8 | main(){ |
9 | }
|
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...
> 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
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.
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 :)
> 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.
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...
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.
@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
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.
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...
@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.
1 | #define WDTO_16MS 0
|
2 | #define WDTO_32MS 1
|
3 | #define WDTO_64MS 2
|
4 | #define WDTO_125MS 3
|
5 | #define WDTO_250MS 4
|
6 | #define WDTO_500MS 5
|
7 | #define WDTO_1S 6
|
8 | #define WDTO_2S 7
|
9 | |
10 | uint8_t Relais_Position=0; |
11 | |
12 | WD_Enable(uint8_t timeout){ |
13 | WDTCSR |= (1<<WDIE) | (1<<WDE); |
14 | WDTCSR |= timeout; |
15 | }
|
16 | |
17 | int main(){ |
18 | while(1){ |
19 | sei(); |
20 | WD_Enable(WDTO_16MS); |
21 | |
22 | ADC_Val = Read_ADC(0); // hier soll der WD zuschlage (tut er auch) |
23 | }
|
24 | return 0; |
25 | }
|
26 | }
|
27 | |
28 | ISR (WDT_vect){ //wird leider nicht abgearbeitet |
29 | /*Abspeichern der Relaisposition vor einem Reset.*/
|
30 | Relais_Position = PORTB; |
31 | }
|
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
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
1 | #define WDTO_16MS 0
|
2 | #define WDTO_32MS 1
|
3 | #define WDTO_64MS 2
|
4 | #define WDTO_125MS 3
|
5 | #define WDTO_250MS 4
|
6 | #define WDTO_500MS 5
|
7 | #define WDTO_1S 6
|
8 | #define WDTO_2S 7
|
9 | |
10 | uint8_t Relais_Position=0; |
11 | |
12 | WD_Enable(uint8_t timeout){ |
13 | MCUSR &= ~(1<<WDRF); |
14 | WDTCSR |= (1<<WDIE) | (1<<WDE); |
15 | WDTCSR |= timeout; |
16 | }
|
17 | |
18 | int main(){ |
19 | while(1){ |
20 | sei(); |
21 | WD_Enable(WDTO_16MS); |
22 | |
23 | ADC_Val = Read_ADC(0); // hier soll der WD zuschlage (tut er auch) |
24 | }
|
25 | return 0; |
26 | }
|
27 | }
|
28 | |
29 | ISR (WDT_vect){ //wird leider nicht abgearbeitet |
30 | /*Abspeichern der Relaisposition vor einem Reset.*/
|
31 | Relais_Position = PORTB; |
32 | }
|
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.