Forum: Mikrocontroller und Digitale Elektronik Timer1 beim ATmega8 auch rückwärts?


von Hermi (Gast)


Lesenswert?

Hallo Leute,
ich muss für ein Wegmesssystem einen Inkrementgeber auswerten, d.h. die 
Schritte Zählen und die Bewegungsrichtung feststellen und den aktuellen 
Messwert auf einem LCD anzeigen. Ich hatte die beiden Signale als 
externe Interrupts angebunden, in der entsprechenden Interruptroutine 
die Richtung ermittelt, eine Variable hoch- bzw. runtergezählt und dann 
den aktuellen Wert zum LCD gesendet. Prinzipiell funktioniert das Ganze, 
aber während des sendens zum LCD gehen Inkremente verloren. Jetzt hab 
ich mir überlegt das Zählen der Inkremente dem Timer1 zu überlassen weil 
der unabhängig vom Programm läuft. das funktioniert auch, aber bei 
Rückwärtsbewegung des Messsystems mus er auch rückwärts zählen.
Jetzt meine Frage: kennt jemand eine Möglichkeit wie ich den Timer1 
rückwärts zählen lassen kann (im PWM- Bertieb macht er das doch auch)?

Ich hab jedenfalls im Datenblatt nichts gefunden und wäre dankbar für 
einen Hinweis.

Grüße: Hermi

von Karl H. (kbuchegg)


Lesenswert?

Hermi schrieb:

> Messwert auf einem LCD anzeigen. Ich hatte die beiden Signale als
> externe Interrupts angebunden, in der entsprechenden Interruptroutine
> die Richtung ermittelt, eine Variable hoch- bzw. runtergezählt und dann
> den aktuellen Wert zum LCD gesendet.

Lass mich raten: du machst die Ausgabe aufs LCD auch innerhalb der ISR?

> Prinzipiell funktioniert das Ganze,
> aber während des sendens zum LCD gehen Inkremente verloren.

Das wundert mich nicht.
Verlagere die Ausgabe in die Hauptschleife und alles wird gut.
Alte Regel: In einer ISR nur das allernotwendigste machen. Alles was 
nicht zeitkritisch ist oder nicht unbedingt in der ISR gemacht werden 
muss, fliegt dort raus.

> Jetzt meine Frage: kennt jemand eine Möglichkeit wie ich den Timer1
> rückwärts zählen lassen kann (im PWM- Bertieb macht er das doch auch)?

Du zäumst das Pferd am falschen Ende auf.
Mach deine SW-Architektur richtig und alles wird gut.

1
...
2
3
volatile uint16_t counter;
4
volatile uint8_t updateLCD;
5
6
ISR( .... )
7
{
8
  // frage die notwendigen Eingänge ab
9
  // einfache und kurze Berechnungen können auch noch gemacht
10
  // werden, wenn die Zeit reicht
11
  counter++;
12
13
14
  // und teile der Hauptschleife mit, dass neue Werte aufs LCD müssen
15
  updateLCD = TRUE;
16
}
17
18
...
19
20
int main()
21
{
22
  ....
23
24
  while( 1 ) {
25
    ...
26
27
    if( updateLCD ) {
28
      updateLCD = FALSE;
29
30
      // mach die Ausgabe aufs LCD, beim Zugriff auf die globalen
31
      // Variablen auf atomaren Zugriff achten! Nicht dass die ISR
32
      // während der Ausgabe die globalen Variablen zwischendurch
33
      // verändert
34
35
      cli();
36
      tmp = counter;
37
      sei();
38
39
      itoa( buffer, tmp, 10 );
40
      lcd_string( buffer );
41
    }
42
  }
43
}

von MeinerEiner (Gast)


Lesenswert?

Übermittelst du die Daten in der Interruptroutine an das LCD? Wenn ja, 
dann ist das normal, dass Schritte verloren gehen.
Wenn nein, stimmt irgendwas nicht, da das Display-Update durch das 
Zählen kurz unterbrochen werden müsste...

von Hermi (Gast)


Lesenswert?

Hallo Leute,
vielen dank für Eure ersten Tipps. Ich habe jetzt das Ganze so 
abgeändert, dass ich in der jeweiligen Interruptroutine die Variable mit 
dem Messwert hoch oder runterzähle, die Erkennung der Bewegungsrichtung 
im Hauptprogramm realisiere und das LCD nur etwa viermal pro Sekunde in 
einer Interruptroutine von timer1 aktualisiere. Jetzt läuft es 
jedenfalls erstmal stabil, aber ich denke Währenfd des sendens an das 
LCD können doch noch Inkremente verlorengehen- weil doch in dieser Zeit 
die Interrupts ausgeschaltet sind.

von Karl H. (kbuchegg)


Lesenswert?

Hermi schrieb:

> jedenfalls erstmal stabil, aber ich denke Währenfd des sendens an das
> LCD können doch noch Inkremente verlorengehen- weil doch in dieser Zeit
> die Interrupts ausgeschaltet sind.

Wenn du es so gemacht hast, wie ich es dir weiter oben gezeigt habe, 
dann müssen die Interrupts aber schon sehr schnell kommen. Konkret kann 
nur in der kurzen Zeitspanne hier
1
      cli();
2
      tmp = counter;
3
      sei();

ein Interrupt verloren gehen. Nur hier sind die Interrupts gesperrt. Und 
das auch nur, wenn 2 so knapp hintereinander kommen, dass sich das mit 
dem Timing nicht mehr anders ausgeht.

Nachdem du dir die aktuellen Werte geholt hast, hast du alle Zeit der 
Welt die Anzeige auf den neuesten Stand zu bringen. Und es gibt auch 
keinen Grund während der Aufbereitung bzw. des Sendens an das LCD die 
Interrupts zu sperren :-) Wenn das LCD ein paar µs später die neuen 
Werte anzeigt, so spielt das keine Rolle. So schnell kann ein Mensch 
sowieso nicht schaun.

von Falk B. (falk)


Lesenswert?

@  Hermi (Gast)


>Messwert auf einem LCD anzeigen. Ich hatte die beiden Signale als
>externe Interrupts angebunden, in der entsprechenden Interruptroutine
>die Richtung ermittelt, eine Variable hoch- bzw. runtergezählt und dann

Möööööp!!!

1.) Fehler: Drehgeber werden durch Abtastung per Timerinterrupt 
ausgewertet. Siehe Artikel.

>aber während des sendens zum LCD gehen Inkremente verloren. Jetzt hab

2.) Fehler. Interrupt-Routinen müssen kurz sein, längere Aufgaben 
werden, nein MÜSSEN, in der Hauptschleife ausgeführt werden, siehe 
Artikel.

>Rückwärtsbewegung des Messsystems mus er auch rückwärts zählen.

Macht eine richtige(tm) Auswertung problemlos.

>Jetzt meine Frage: kennt jemand eine Möglichkeit wie ich den Timer1
>rückwärts zählen lassen kann (im PWM- Bertieb macht er das doch auch)?

Käse.

MfG
Falk

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.