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