Forum: Mikrocontroller und Digitale Elektronik Timer1 CTC Problem


von Michael N. (garril)


Lesenswert?

Hallo, ich bekomme leider in meiner ISR das Problem, dass der Compiler 
meldet, dass er die Variablen nicht kennt. Es sind jedoch alle mit 
volatile gekennzeichnet...
1
// Deklaration verschiedener Funktionen
2
3
4
int main(void)
5
{
6
    volatile unsigned char actual_row=0;
7
  volatile unsigned char static_field[10][3];     //static_field[x][y]: x=row from top; y=color. 0=red, 1=green, 2=blue
8
  volatile unsigned char variable_field[8][3];   //variable_field[x][y]: x=row from top; y=color. 0=red, 1=green, 2=blue
9
  volatile unsigned char border[10];
10
// Timer 0 konfigurieren
11
  TCCR1A = 0;
12
  TCCR1B = (1<<WGM12)|(1<<CS11); // CTC Modus, Prescaler 8
13
  OCR1A = 125-1; // CTC-Event all 1 ms, was ist Unterschied zw. OCR1AH/L und OCR1BH/L?
14
15
  // Compare Interrupt erlauben
16
   TIMSK |= (1<<OCIE1A);
17
 
18
  // Global Interrupts aktivieren
19
  sei();
20
21
// Hier folgt der restliche Programmcode. Lediglich Befüllung der Arrays.
22
23
}
24
25
ISR (TIMER1_COMPA_vect)
26
{
27
  unsetRow();
28
  _delay_us(50);
29
  setCol(static_field[actual_row][0],static_field[actual_row][1],static_field[actual_row][2],border[actual_row]);
30
  setRow(actual_row);
31
  if (actual_row<9) {
32
    actual_row++;
33
  }
34
  else {
35
    actual_row=0;
36
  }
37
}

Die Fehler:
static_field, actual_row, border undeclared

Wo liegt mein Fehler?


Des Weiteren würde es mich noch interssieren, wo der Unterschieden 
zwischen OCR1AH/L und OCR1BH/L liegt. Sind ja beides 16 Bit Register mit 
denen dann der Timer verglichen wird. Aber warum 2 dieser 
Vergleichsregister?

von Magnus M. (magnetus) Benutzerseite


Lesenswert?

Michael N. schrieb:
> Die Fehler:
> static_field, actual_row, border undeclared
>
> Wo liegt mein Fehler?

Da du die Variablen innerhalb der main() deklariert hast, sind sie auch 
nur innerhalb dieser gültig / bekannt.

von Karl H. (kbuchegg)


Lesenswert?

Michael N. schrieb:

> Wo liegt mein Fehler?

Das du nie gelernt hast, was Gültigkeitsbereiche sind (C-Grundlagen).

Die Sichtbarkeit bzw. Gültigkeit einer Variablen ist begrenzt! Nicht 
jede Variable ist überall sichtbar.

Im wesentlichen kann man sagen, dass ein umschliessender {-} Block die 
Sichtbarkeit und Gültigkeit einer Variablen begrenzt. In

  if( i == 5 )
  {
    int j;
    j = 8;
  }

kommt die Variable j mit Beginn des { - Blockes zum Leben, existiert 
dann in diesem Block und verschwindet beim } wieder. Genauso ist die 
Sichtbarkeit geregelt: Diese Variable ist nur innerhalb dieses { } 
Blocks sichtbar. Von ausserhalb dieses Blocks existiert diese Variable 
nicht und sie ist auch von ausserhalb nicht sichtbar.

Und das gilt auf allen Ebenen!

In
1
void foo()
2
{
3
  int a, b;
4
5
  ...
6
}

existieren die Variablen a und b nur innerhalb der Funktion und sie sind 
auch nur innerhalb dieser Funktion sichtbar. Denn selbstverständlich ist 
auch dieses { } ein Block von Anweisungen mit genau den gleichen 
Eigenschaften wie jeder andere { } Block.

Hast du also
1
int main(void)
2
{
3
  volatile unsigned char actual_row=0;
4
5
  ...
6
}
7
8
ISR (TIMER1_COMPA_vect)
9
{
10
  ...
11
12
  ...  actual_row ...
13
14
}

dann existiert actual_row aus Sicht der ISR-Funktion schlicht und 
ergreifend nicht. Die Sichtbarkeit dieser Variablen ist durch den Block 
in main() begrenzt. Ausserhalb dieser Funktion ist die Variable nicht 
sichtbar.

Du musst also die Variable aus diesem Funktionsblock 'herausheben', 
damit sie sowohl in main() als auch innerhalb der ISR Funktion sichtbar 
ist
1
volatile unsigned char actual_row=0;
2
3
int main(void)
4
{
5
6
  ...
7
}
8
9
ISR (TIMER1_COMPA_vect)
10
{
11
  ...
12
13
  ...  actual_row ...
14
15
}


und nein: volatile hat damit erst mal nichts zu tun. volatile löst ein 
ganz anderes Problem.

von Karl H. (kbuchegg)


Lesenswert?

Michael N. schrieb:

> Des Weiteren würde es mich noch interssieren, wo der Unterschieden
> zwischen OCR1AH/L und OCR1BH/L liegt. Sind ja beides 16 Bit Register mit
> denen dann der Timer verglichen wird. Aber warum 2 dieser
> Vergleichsregister?


Damit man sich gegebenenfalls eben mit 2 Vergleichen an den laufenden 
Timer koppeln kann.
Die Frage ist ungefähr so sinnvoll, wie die Frage:
Ich habe da eine Uhr die über eine Schalteinrichtung verfügt. Ich kann 
am Rand meiner Uhr einen kleinen roten Pfeil einstellen und wenn der 
kleine Zeiger der Uhr auf genau diesen Pfeil zeigt, dann schaltet diese 
Uhr etwas.
Soweit so gut, aber warum gibt es diese ganze Einrichtung doppelt?

Und die Antwort darauf ist: weil es eben manchmal sinnvoll sein kann, 2 
mal am Tag bei Übereinstimmung des kleinen Zeigers mit einer Markierung 
etwas zu schalten.

Kein Mensch sagt, dass du das tun musst. Aber wenn du es brauchst, bist 
du froh wenn du es hast.

von Michael N. (garril)


Lesenswert?

Hm, logisch...Ich habe die Deklarationen aus der main rausgenommen.

Zum doppelten Vergleichsregister: Aber habe ich es richtig verstanden, 
dass sich der Timer nach erreichung dieses wertes normal zurücksetzt? 
Oder ist das nur optional.

Denn wenn ich einen Zähler bis zB 250 habe. Und bei 100 und 200 eine ISR 
auslösen möchte, macht es keinen Sinn, wenn die erste ISR den Zähler 
zurücksetzt. Deshalb meine Nachfrage.

von amateur (Gast)


Lesenswert?

Der Zähler 1 hat ein Zählregister und zwei Vergleichsregister.
Dies sind OCR1A und OCR1B (jeweils 16 Bit breit).
Ich kenne leider Deinen Prozessor nicht mit Vornamen aber oft haben die 
Teile einen eigenen Interrupt und einen eigenen Ausgang, wenn es denn 
gewünscht wird.
Normalerweise ist dies, mit allem Drum und Dran, im Manual beschrieben 
und bebildert.

von Karl H. (kbuchegg)


Lesenswert?

Michael N. schrieb:
> Hm, logisch...Ich habe die Deklarationen aus der main rausgenommen.
>
> Zum doppelten Vergleichsregister: Aber habe ich es richtig verstanden,
> dass sich der Timer nach erreichung dieses wertes normal zurücksetzt?

Nicht 'dieses Wertes'.
Sondern 'Stimmt der Inhalt des Zählregisters mit dem Inhalt des OCR1A 
Registers überein (ein konkretes Register, nicht einfach irgendeines), 
dann wird der Timer im nächsten Schritt auf 0 gesetzt'.

Ja, genau so ist der CTC Modus definiert.

Damit hast du dann noch ein OCR1B Register übrig, mit dem du bei 
bestimmten Zählerständen eine weitere Aktion auslösen lassen kannst.


> Denn wenn ich einen Zähler bis zB 250 habe. Und bei 100 und 200 eine ISR
> auslösen möchte, macht es keinen Sinn, wenn die erste ISR den Zähler
> zurücksetzt.

Das Zurücksetzen ist zwanghaft an OCR1A gebunden. OCR1B kann das nicht.

von omg (Gast)


Lesenswert?

Michael N. schrieb:
> Oder ist das nur optional.

Alles ist optional. Man verwendet die zur Verfügung gestellten 
Funktionen alle zusammen oder einzeln oder in Kombination oder überhaupt 
nicht.

Die zur Verfügung stehenden Funktionen entnimmt man dem Datenblatt des 
zugehörigen µC. Bei Nichtverstehen desselben würd ich konkrete Fragen 
mit Bezug auf desselben (Datenblattes) stellen.

von Michael N. (garril)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Damit hast du dann noch ein OCR1B Register übrig, mit dem du bei
> bestimmten Zählerständen eine weitere Aktion auslösen lassen kannst.

Danke, jetzt habe ich den Sinn verstanden.

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.