Forum: Compiler & IDEs Timer0-Problem


von Max  . (ueps)


Lesenswert?

Hallo,

ich möchte einen Timer dazu nutzen, um auf ein Ereignis reagieren zu 
können.

Also es soll so ablaufen:

1. Stelle Timer
2. Mache irgendwas, warte auf einen besonderen Zustand
3a. Zustand eingetreten => Timer abschalten, weitermachen
3b. Zustand nicht eingetreten innerhalb Zeit des Timers => in 
Fehlerroutine springen

Nun habe ich mir gedacht, ich mache das über meinen Timer0, den ich im 
Compare-Modus laufen lasse.

µC: ATmega169, Betriebsart: 8MHz etc.

Code während init:
1
      
2
TIMSK0 |= (1<<OCIE0A);

Code zur Laufzeit:
1
OCR0A = iDelayMs;
2
TCCR0A = (1<<CS00)|(1<<CS02)|(1<<WGM00)|(0<<COM0A1)|(0<<COM0A0);      
3
  
4
Warte auf XYZ
5
  
6
TCCR0A = (0<<CS00)|(0<<CS02);

und die ISR:
1
SIGNAL(TIMER0_COMP_vect)
2
{
3
TCCR0A = (0<<CS00)|(0<<CS02);
4
ausfError();
5
}

iDelayMs enthält den Wert, der bei der Taktung und der 
Prescaler-Einstellung für die entsprechende Millisekundenzeit steht die 
ich brauche.
Berechnung: ZEIT * FOSC : 1000 : 1024

Nun mein Problem: Das Programm springt IMMER in die ISR, egal wie lang 
ich den Counter stelle.
Liegt es daran, dass ich an Port B gleichzeitig LEDs schalte (also DDRD 
= 0xFF und PORTB wird inkrementiert?). Dachte, dass ich mit 
(0<<COM0A1)|(0<<COM0A0) die Portaktivität für den Timer deaktiviert 
habe.

Bin für jede Hilfe dankbar!

gruß
Y

von Max  . (ueps)


Lesenswert?

habe es nun so umgeändert:
1
  // Timer für die Synchronisation starten
2
  TCNT0 = 0;                  // Setzt den aktuellen Zählerstand auf 0
3
  OCR0A = iDelayMs;              // Setzt den errechneten mS-Wert ins Compare-Register
4
  TCCR0A &= ~((1<<WGM00)&(1<<COM0A1)&(1<<COM0A0)&(1<<CS01));
5
  TCCR0A = (1<<CS00)|(1<<CS02)|(1<<WGM01);
6
  
7
  // do anything
8
  
9
  TCCR0A &= ~((1<<CS00)&(1<<CS02));

vorweg: es geht immernoch nicht so wie ich mir das vorstelle.. und ich 
weiß leider immernoch nicht wo der fehler liegt.

was ich allerdings seltsam finde: er schaltet mir portB-pin4 obwohl ich 
doch mit COM0A1 und COM0A0 gesagt habe er soll den port NICHT schalten!

von sous (Gast)


Lesenswert?

Ohne, dass ich mir Deinen Quellcode jetzt zu genau anschaue, aber:
Du schreibst, die ISR wird aufgerufen (was für mich heißt, der Timer 
wurde irgendwie korrekt initialisiert, zählt und löst einen Interrupt 
aus).

Dann wird bei

"Warte auf XYZ"

irgendwas gemacht, danach wird der Timer angehalten. Du schreibst: ISR 
wird immer angesprungen und fragst uns nun, ob

"Warte auf XYZ" schuld daran ist?!?

Dann wirst Du uns wohl verraten müssen, was "Warte auf XYZ" nun wirklich 
ist und macht, sonst können wir nur Lottoscheine ausfüllen...

von Tobi (Gast)


Lesenswert?

Ihc verstehe dien Problem nicht ganz. Natürlich springt er die ISR an. 
der Timer wird ja irgendwann den Compare Wert erreichen, egal, wie groß 
er ist.

Zu den Pins: Schalte sie mal explitit als Eingang.

von sous (Gast)


Lesenswert?

Wenn ich das richtig verstehe, dann soll ja nach 'Warte auf XYZ'
mittels der Zeile

TCCR0A = (0<<CS00)|(0<<CS02);

der Timer wieder abgestellt werden (Taktquelle aus), so dass der Zähler 
dann nicht mehr zählt. Allerdings sehe ich zu wenig drumherum-Info, um 
sagen zu können, warum hier was passiert.

von Ueps (Gast)


Lesenswert?

also mein programm soll quasi folgendes machen:

ich habe zwei systeme die sich gegenseitig synchronisieren (bzw. ihren 
status vergleichen und bei differenz mit fehlermeldung abschalten). grob 
gesehen machen beide programme nicht anders als einen zähler 
hochzuzählen (0-255) und dann den wert an 8 an portb angeschlossenen 
LEDs auszugeben.
somit habe ich portB mittels
1
DDRB = 0xff
als ausgang geschaltet. anschließend senden sie sich gegenseitig den 
aktuellen status (über usart).. die routine für die synchronisation seht 
ihr unten.

warum ändert sich dann der wert an portb? in der ISR, welche ja eine 
fehlerroutine aufruft, wird an portb nichts verändert..

isr:
1
SIGNAL(TIMER0_COMP_vect)
2
{
3
  TCCR0A &= ~((1<<CS00)&(1<<CS02));
4
  ausfError();
5
}

fehlerroutine:
1
void ausfError(){
2
  wdt_disable();              // Watchdog deaktivieren
3
  
4
  while(1){
5
    // Fehlercode an PortD ausgeben. Fehlercode laut Tabelle
6
    PORTD = 0xFF;
7
    _delay_loop_2(65535);
8
    _delay_loop_2(65535);
9
    _delay_loop_2(65535);
10
    _delay_loop_2(65535);
11
    PORTD = 0x00;
12
    _delay_loop_2(65535);
13
    _delay_loop_2(65535);
14
    _delay_loop_2(65535);
15
    _delay_loop_2(65535);
16
  }
17
}

das "do anything" sieht so aus:
1
// Schleife zur überprüfung ob Synchronisation stattgefunden hat
2
  while(!iSyncDone){
3
    if(isCharAvailable() == 1){      // Wenn Data empfangen..
4
      string[count++] = receiveChar();  // prüfen ob Länge des Strings der erwarteten Länge entspricht
5
      if(count > 1){            // Falls nicht, Fehler melden
6
        stdError();
7
      }
8
      else{                // sonst Status vergleichen 
9
        if(string[0] != cStatus){
10
          syncError();
11
        }
12
        string[0] = '\0';
13
        iSyncDone = 1;
14
      }
15
    }
16
  }

wenn ich statt dem counter vor der schleife einfach ein delay von <5ms 
anbringe, dann läuft das programm wunderbar durch.

komplettabschnitt des codes:
1
void doSync(){
2
  // Hilfsvariablen initialisieren
3
  char string[64];
4
  unsigned char count = 0;
5
  int iSyncDone = 0;
6
7
  // aktuellen Status senden
8
  if(cStatus <= iMaxStat)
9
    sendChar(cStatus);
10
  else
11
    stdError();
12
  
13
  // Wartezeit, falls nicht im Debug-Mode
14
  //if(!iDebug)
15
    //_delay_loop_2(10000);
16
  
17
  // Watchdog  zurück setzen um keinen Alarm beim Warten auf Statusantwort zu schlagen
18
  wdt_reset();
19
  
20
  // Timer für die Synchronisation starten
21
  TCNT0 = 0;                  // Setzt den aktuellen Zählerstand auf 0
22
  OCR0A = iDelayMs;              // Setzt den errechneten ms-Wert ins Compare-Register
23
  TCCR0A &= ~((1<<WGM00)&(1<<COM0A1)&(1<<COM0A0)&(1<<CS01));
24
  TCCR0A = (1<<CS00)|(1<<CS02)|(1<<WGM01);
25
  
26
  // Schleife zur überprüfung ob Synchronisation stattgefunden hat
27
  while(!iSyncDone){
28
    if(isCharAvailable() == 1){      // Wenn Data empfangen..
29
      string[count++] = receiveChar();  // prüfen ob Länge des Strings der erwarteten Länge entspricht
30
      if(count > 1){            // Falls nicht, Fehler melden
31
        stdError();
32
      }
33
      else{                // sonst Status vergleichen 
34
        if(string[0] != cStatus){
35
          syncError();
36
        }
37
        string[0] = '\0';
38
        iSyncDone = 1;
39
      }
40
    }
41
  }
42
  
43
  TCCR0A &= ~((1<<CS00)&(1<<CS02));  
44
}

ebenso habe ich bei benutzung des counters ein synchronitätsproblem. ein 
system meldet, dass das system einen falschen status bekommen hat, 
worauf das andere sich dann korrekt mit "anderes system reagiert nicht" 
verabschiedet. allerdings kommt das synchronitätsproblem NICHT zustande, 
wenn ich den counter weg lasse, dafür aber ein delay von <5ms vor der 
schleife einbaue.

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.