Forum: Mikrocontroller und Digitale Elektronik watchdog ohne Totalreset?


von Egon M. (kpc)


Lesenswert?

Hallo,

Im Tutorial über den Watchdog finde ich leider nur, daß er einen 
Totalreset auslöst - oder habe ich da eine Möglichkeit übersehen?

Mein Problem:
Eine Schaltung zur Auswertung von Meßwerten soll gegen Sensorausfall 
abgesichert werden.

Wenn z.B. der High-Zustand an einem Sensor länger als eine Sekunde 
dauert, dann sind die gezählten Counts wertlos und das Zählen kann 
abgebrochen werden. Es sollte dann aber das Programm zum nächsten Sensor 
springen - und nicht etwa von vorn beginnen.
Ich wollte nicht gern in die Zählschleife eine zusätzliche Abfrage nach 
einem Grenzwert intgerieren, weil das Zeit kostet und die Zahl der 
"Nutz"-counts mindert.

Es wäre schön, wenn man dem WD sagen könnte: nach 1 sec abbrechen und zu 
einen anderen Programmpunkt springen. Aber das geht wohl nicht, oder?

Vor Timer-Interrupts wollte ich mich gern drücken, weil ich zuwenig 
davon verstehe und mein Programm zu einem größeren Programm gehört, 
dessen Interruptmamagement ich vielleicht mit einem unpassendes cli(); 
störe.

Viele Grüße
Egon

von Sven P. (Gast)


Lesenswert?

Egon Müller schrieb:
> Hallo,
>
> Im Tutorial über den Watchdog finde ich leider nur, daß er einen
> Totalreset auslöst - oder habe ich da eine Möglichkeit übersehen?
Nein.

> Vor Timer-Interrupts wollte ich mich gern drücken, weil ich zuwenig
> davon verstehe und mein Programm zu einem größeren Programm gehört,
> dessen Interruptmamagement ich vielleicht mit einem unpassendes cli();
> störe.
Na das is dann natürlich ein Argument...

Ich würd sagen, Timer bzw. ein Timer im Capture-Modus wär dein Ding.

von Stefan E. (sternst)


Lesenswert?

Sven P. schrieb:

>> Im Tutorial über den Watchdog finde ich leider nur, daß er einen
>> Totalreset auslöst - oder habe ich da eine Möglichkeit übersehen?
> Nein.

Hängt vom konkreten AVR ab. Bei neueren Modellen kann der Watchdog auch 
einfach nur einen Interrupt auslösen.

Ob das allerdings im konkreten Fall irgendwie besser ist, als ein 
normaler Timer-Interrupt, wage ich zu bezweifeln.

von Egon M. (kpc)


Lesenswert?

Hallo Sven

Leider hat input capture an meinem ATmega16 nur einen einzigen Eingang 
(ICP 0 Port D6), deshalb hatte ich früher über spezielle IC's die 
Sensoreingänge reihum auf Port D6 schalten müssen.
Die derzeitige Schaltung nach dem Motto "ein Seensor-ein Port" läßt 
daher kein input capture zu.


Gruß
Egon

von Egon M. (kpc)


Lesenswert?

>
> Hängt vom konkreten AVR ab. Bei neueren Modellen kann der Watchdog auch
> einfach nur einen Interrupt auslösen.
>
Mein Testboard enthält einen ATmega644p - ob der das kann?
[ich habe das Manual nicht - müßte es erst downloaden]
 Gruß
Egon

>
> Ob das allerdings im konkreten Fall irgendwie besser ist, als ein
> normaler Timer-Interrupt, wage ich zu bezweifeln.

Meine Sorge ist, die anderen Interrupts nicht zu stören

von Stefan E. (sternst)


Lesenswert?

Egon Müller schrieb:

> Die derzeitige Schaltung nach dem Motto "ein Seensor-ein Port" läßt
> daher kein input capture zu.

Eine Timeout-Funktionalität auf Basis eines Timers bräuchte auch kein 
Input-Capture.

> Ich wollte nicht gern in die Zählschleife eine zusätzliche Abfrage nach
> einem Grenzwert intgerieren, weil das Zeit kostet und die Zahl der
> "Nutz"-counts mindert.

Du müsstest nur zusätzlich eine Variable testen (z.B. auf Null). Das 
braucht bloß eine Hand voll Cycles. Würde das wirklich nennenswert zu 
Buche schlagen?

von Stefan E. (sternst)


Lesenswert?

> müßte es erst downloaden

Dann tue das. Du glaubst doch nicht ernsthaft, komplett ohne das 
Datenblatt auskommen zu können, oder?

von Egon M. (kpc)


Lesenswert?

Stefan Ernst schrieb:
>> müßte es erst downloaden
>
> Dann tue das. Du glaubst doch nicht ernsthaft, komplett ohne das
> Datenblatt auskommen zu können, oder?

Ist auch nicht nötig, das Manual für meinen wichtigsten Prosessor, 
ATmega 16, habe ich zur Hand, das vom ATmega644 ist auf einem PC, an den 
ich jetzt nicht herankomme.

mfg
Egon

von Egon M. (kpc)


Lesenswert?

Stefan Ernst schrieb:
.
>
> Du müsstest nur zusätzlich eine Variable testen (z.B. auf Null). Das
> braucht bloß eine Hand voll Cycles. Würde das wirklich nennenswert zu
> Buche schlagen?

Diesen Test müßte ich aber doch in die Zählschleife hineinschreiben und 
dann sind es ebensoviele Takte wie die Sensorabfrage, d.h. die Anzahl 
der "geernteten" Counts halbiert sich?

 Vielleicht sollte ich es doch mal mit einem zählergesteuerten Interrupt 
versuchen und zusehen, ob das übrige Programm noch funktioniert.

Gruß Egon

von Eddy C. (chrisi)


Lesenswert?

Nicht probieren, sondern wissen! Ohne Systemüberblick gibt's früher oder 
später Probleme.

Zeig doch mal die Routine, die die Counts "erntet". Da läßt sich doch 
was verbessern!

von Stefan E. (sternst)


Lesenswert?

Egon Müller schrieb:

> Diesen Test müßte ich aber doch in die Zählschleife hineinschreiben und
> dann sind es ebensoviele Takte wie die Sensorabfrage, d.h. die Anzahl
> der "geernteten" Counts halbiert sich?

Was genau macht denn diese Zählschleife? Zählen so lange ein Portpin 
einen bestimmten Pegel hat?
Dann gäbe es noch folgende Variante:
Zwischen Sensor und Portpin einen Widerstand machen. Der Timer-Interrupt 
setzt den Portpin auf Ausgang und den entgegengesetzten Pegel und 
erzwingt somit einen Abbruch der Zählschleife. Zusätzlich wird ein Flag 
gesetzt, an dem du dann nach der Zählschleife erkennen kannst, dass die 
Schleife abgebrochen wurde.

von Egon M. (kpc)


Lesenswert?

Eddy Current schrieb:
> Nicht probieren, sondern wissen! Ohne Systemüberblick gibt's früher oder
> später Probleme.
>
> Zeig doch mal die Routine, die die Counts "erntet". Da läßt sich doch
> was verbessern!

Ist zunächst als while-Schleife realisiert, weil ich z.Zt. noch 
danebensitze und die Sensorfunktion beobachten kann.
Es funktioniert die nackte Abfrage:
while ((PIND & 128))
  (high = high + 1);
    };  //end of for

Ich müßte also noch eine Abfrage unterbringen, ob high < limit ist, um 
aus der Schleife herauszukommen. In Basic würde man ohne Unlustgefühle 
"goto" verwenden. Ich glaube inzwischen, daß sich ein Interrupt doch 
besser macht.


@hi Stefan
Wäre sicher eine Möglichkeit. Aber: wenn ich nun doch auf einen 
Interrupt setze, komme ich dann nicht ohnehin aus der Schleife heraus?
Mir ist bloß nach der Tutoriallektüre nicht ganz klar, wohin das 
Programm aus der ISR springt. Ich würde innerhalb der ISR der Variablen 
"high" einen Wert zuweisen und dann zu dem Statement unmittelbar nach 
der while-Schleife springen wollen. Geht das?

Viele Grüße
Egon

von Karl H. (kbuchegg)


Lesenswert?

Egon Müller schrieb:

> Es funktioniert die nackte Abfrage:
> while ((PIND & 128))
>   (high = high + 1);
>     };  //end of for

Du könntest zb einen Timer als Zähler benutzen.
Dadurch kriegst du in der Schleife ein paar Takte frei um die 
Abbruchbedingung zu testen

von Eddy C. (chrisi)


Lesenswert?

Wenn der Zähler beim inkremenentieren null erreicht, ist er 
übergelaufen: Timeout, oder so:

if (++high == 100)  // Count and check timeout
   goto Timeout;

Je nach Datentyp von 'high' kann bei Übertrag vom low-Byte zum high-Byte 
(16 Bit) für einen Count ein anderes Timing entstehen. Wenn 'high' nur 
ein Byte ist, paßt alles. Oder sehe ich da den inner Loop einer 
verschachtelten Schleife?

von Stefan E. (sternst)


Lesenswert?

Egon Müller schrieb:

> Wäre sicher eine Möglichkeit. Aber: wenn ich nun doch auf einen
> Interrupt setze, komme ich dann nicht ohnehin aus der Schleife heraus?

Nein, nicht dauerhaft.

> Mir ist bloß nach der Tutoriallektüre nicht ganz klar, wohin das
> Programm aus der ISR springt.

Das Programm springt genau an die Stelle zurück, von wo es gekommen ist, 
also wieder in die Schleife.

> Ich würde innerhalb der ISR der Variablen
> "high" einen Wert zuweisen und dann zu dem Statement unmittelbar nach
> der while-Schleife springen wollen. Geht das?

"Gehen" tut praktisch alles irgendwie, aber:
Ich möchte dir ja nicht zu nahe treten, aber da du ja anscheinend nicht 
mal damit vertraut bist, was ein Interrupt überhaupt genau ist und 
macht, liegt das außerhalb deiner Möglichkeiten. Versuch lieber, das 
erstmal irgendwie "konventionell" zu lösen.

von Peter D. (peda)


Lesenswert?

Egon Müller schrieb:
>
1
> while ((PIND & 128))
2
>   (high = high + 1);
3
>     };  //end of for
4
>

Das ist nicht gerade der Brüller.
Woher weißt Du, mit welcher Frequenz "high" zählt?
Nimm nen Timer, dann weißt Du es und obendrein steigt Deine Auflösung.

Z.B.:
1
  while( !(PIND & 1<<PD7));  // warte auf high
2
  // timer start
3
  while( (PIND & 1<<PD7) && !(TIFR & 1<<TOV1));  // warte auf low oder T1 overflow
4
  // timer stop und auslesen

Du kriegst von Atmel kein Geld zurück, wenn Du die Timer nicht benutzt.


Peter

von Egon M. (kpc)


Lesenswert?

Peter Dannegger schrieb:

>
> Du kriegst von Atmel kein Geld zurück, wenn Du die Timer nicht benutzt.
>
>
> Peter

Das ist richtig. Und außerdem sind die Zähler doch sehr bequem.

Vielen Dank für Eure Hilfe, ich habe das Problem jetzt mit einem Zähler 
gelöst.

Allerdings gibt es noch eionen Wermutstropfen: Das Auslesen des 
16-bit-Zählers funktioniert bei mir einfach nicht.
Ich habe zuerst (wie im Manual verlangt), den Low-Teil (TCNT1L) 
ausgelesen und danach den Rest, das liefert Unsinn. Nur wenn ich den 
Low-Teil von TCNT1 gar nicht anfasse, dann gibt es stabile und plausible 
Werte (muß allerdings noch nachgemessen werden).

Hier die nicht funktionierende Version:

unsigned long highabfrage(void)
{
    unsigned long high = 0;
    DDRD &= 127;                          // PORTD7 wird Eingang
    while ( !(PIND & 1<<PD7));            // warte auf high

  TCCR1B |=  (1<<CS10) | (1<<CS12);  // Timerstart mit 1/1024

  while ((PIND & 1<<PD7) && !(TIFR1 & 1<<TOV1)); // warte auf
                                           //  low oder T-overflow
    TCCR1B = 0;                            // Timer stop
    high = TCNT1L + (TCNT1H<<8);           // auslesen
    return (high); }

Wenn ich in der vorletzten Zeile den Summanden TCNT1L einfach weglasse, 
funktioniert es. Nun könnte man zwar den Low-Anteil vernachlässigen, 
aber unschön ist es doch.
Ich bin davon ausgegangen, daß der Timer bei jedem Neustart bei Null 
beginnt; ihn vorher explizit auf Null zu setzen. hat nichts gebracht.

Kann mir vielleicht jemand schreiben, was ich da falsch mache?

Viele Grüße
Egon

von Stefan E. (sternst)


Lesenswert?

1
high = TCNT1L + (TCNT1H<<8);
Bei sowas hast du keine Kontrolle darüber, welches Register nun 
tatsächlich zuerst gelesen wird. Nimm einfach den üblichen Weg:
1
high = TCNT1;

> Ich bin davon ausgegangen, daß der Timer bei jedem Neustart bei Null
> beginnt;

Nein, du musst ihn schon selber wieder auf Null setzen.
Außerdem musst du auch noch das Overflow-Flag wieder löschen.

PS: Warum eigentlich long? Der Timer hat nur 16 Bit.

von Egon M. (kpc)


Lesenswert?

Hat sich erledigt!
Ich hatte nicht daran gedacht, daß man bei dem Timer in TIVR1
das Overflow-Bit TOV1 manuell zurücksetzen muß, wenn der Interrupt nicht 
ausgeführt wird.

Nun sieht es besser aus.



Also nochmals vielen Dank für Eure freundliche Hilfe!

Gruß
Egon

von Egon M. (kpc)


Lesenswert?

Egon Müller schrieb:
> Hat sich erledigt!
>
> Nun sieht es besser aus.
>
> Gruß
> Egon


April - April!
Nichts funktioniert, der Zähler benimmt sich wie Zufallszahlengenerator!

Ich mache einen neuen Thread auf, nebenan, bei gcc, wo ja die Sache mit 
dem Watchdog eigentlich auch hingehört hätte und unter der passenderen 
Überschrift "Timer... ".

Viele Grüße
Egon

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.