mikrocontroller.net

Forum: Compiler & IDEs Timer0-Problem


Autor: Max  • (ueps)
Datum:

Bewertung
0 lesenswert
nicht 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:
      
TIMSK0 |= (1<<OCIE0A);

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

und die ISR:
SIGNAL(TIMER0_COMP_vect)
{
TCCR0A = (0<<CS00)|(0<<CS02);
ausfError();
}

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

Autor: Max  • (ueps)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
habe es nun so umgeändert:
  // Timer für die Synchronisation starten
  TCNT0 = 0;                  // Setzt den aktuellen Zählerstand auf 0
  OCR0A = iDelayMs;              // Setzt den errechneten mS-Wert ins Compare-Register
  TCCR0A &= ~((1<<WGM00)&(1<<COM0A1)&(1<<COM0A0)&(1<<CS01));
  TCCR0A = (1<<CS00)|(1<<CS02)|(1<<WGM01);
  
  // do anything
  
  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!

Autor: sous (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: Tobi (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: sous (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Ueps (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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
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:
SIGNAL(TIMER0_COMP_vect)
{
  TCCR0A &= ~((1<<CS00)&(1<<CS02));
  ausfError();
}

fehlerroutine:
void ausfError(){
  wdt_disable();              // Watchdog deaktivieren
  
  while(1){
    // Fehlercode an PortD ausgeben. Fehlercode laut Tabelle
    PORTD = 0xFF;
    _delay_loop_2(65535);
    _delay_loop_2(65535);
    _delay_loop_2(65535);
    _delay_loop_2(65535);
    PORTD = 0x00;
    _delay_loop_2(65535);
    _delay_loop_2(65535);
    _delay_loop_2(65535);
    _delay_loop_2(65535);
  }
}

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

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

komplettabschnitt des codes:
void doSync(){
  // Hilfsvariablen initialisieren
  char string[64];
  unsigned char count = 0;
  int iSyncDone = 0;

  // aktuellen Status senden
  if(cStatus <= iMaxStat)
    sendChar(cStatus);
  else
    stdError();
  
  // Wartezeit, falls nicht im Debug-Mode
  //if(!iDebug)
    //_delay_loop_2(10000);
  
  // Watchdog  zurück setzen um keinen Alarm beim Warten auf Statusantwort zu schlagen
  wdt_reset();
  
  // Timer für die Synchronisation starten
  TCNT0 = 0;                  // Setzt den aktuellen Zählerstand auf 0
  OCR0A = iDelayMs;              // Setzt den errechneten ms-Wert ins Compare-Register
  TCCR0A &= ~((1<<WGM00)&(1<<COM0A1)&(1<<COM0A0)&(1<<CS01));
  TCCR0A = (1<<CS00)|(1<<CS02)|(1<<WGM01);
  
  // Schleife zur überprüfung ob Synchronisation stattgefunden hat
  while(!iSyncDone){
    if(isCharAvailable() == 1){      // Wenn Data empfangen..
      string[count++] = receiveChar();  // prüfen ob Länge des Strings der erwarteten Länge entspricht
      if(count > 1){            // Falls nicht, Fehler melden
        stdError();
      }
      else{                // sonst Status vergleichen 
        if(string[0] != cStatus){
          syncError();
        }
        string[0] = '\0';
        iSyncDone = 1;
      }
    }
  }
  
  TCCR0A &= ~((1<<CS00)&(1<<CS02));  
}

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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.