Forum: Mikrocontroller und Digitale Elektronik Attiny2313, Timer 1 Starten, 1Minute, Fehler: left-hand operand of comma expression has no effect


von Matze (Gast)


Lesenswert?

Hallo,

Ich möchte den Timer 1 (16Bit) eines Attiny 2313 benutzen um ca eine 
Minute zu messen.

Danach möchte ich die Ausgänge abschalten...

Nun bekomme ich oft den Fehler:
left-hand operand of comma expression has no effect

Dabei muss ich doch den Timer richtig einstellen.
Hier mein Programm:
1
#include <avr/io.h>
2
#define F_CPU 1000000UL    // 1 MHz (fuer delay.h)
3
#include <util/delay.h>
4
5
6
int main(void)
7
{
8
  PORTD = 0x00;      //Pin für Taster und ADC(Reset) als Eingang
9
  DDRD  = 0xff;
10
  PORTB = 0x00;
11
  DDRB  = 0x00;
12
  //-------TIMER-1----------------------------------
13
  TCCR1A  &= (0<<COM1A0,0<<COM1A1);  // CTC Modus
14
  TCCR0B &= (0<<ICNC1,0<<ICES1,0<<CS11);
15
  TCCR0B |= (1<<WGM12,1<<CS10,1<<CS12);  // Prescaler 1024
16
  OCR1A = 0x0400;                    //Zählen bis 1024;
17
  //------> Timer läuft nun
18
  int lauft=0;
19
    while(1)
20
    { 
21
          lauft = TIFR&(1<<OCF1A);
22
          if(lauft)
23
          {
24
            PORTD=0x00;
25
            while(1)
26
            {
27
              ;
28
            }
29
            TIFR |= (1<<OCF1A);
30
          }
31
          else
32
          {
33
            PORTD=0x55
34
          }      
35
36
    }
37
}
Da PORTD immer auf 0x55 geht, läuft der Timer wohl nicht.

Ich komm nicht auf den Fehler.

Danke dür eure Hilfe.

von Karl H. (kbuchegg)


Lesenswert?

Matze schrieb:

> Nun bekomme ich oft den Fehler:
> left-hand operand of comma expression has no effect
>
> Dabei muss ich doch den Timer richtig einstellen.

Schon.
Aber nicht so
1
TCCR0B |= (1<<WGM12,1<<CS10,1<<CS12);

sondern so
1
TCCR0B |= (1<<WGM12) | (1<<CS10 ) | (1<<CS12);

und natürlich die anderen auch.

von Marc (gierig) Benutzerseite


Lesenswert?

Matze schrieb:
> TCCR1A  &= (0<<COM1A0,0<<COM1A1);  // CTC Modus
>   TCCR0B &= (0<<ICNC1,0<<ICES1,0<<CS11);
>   TCCR0B |= (1<<WGM12,1<<CS10,1<<CS12);  // Prescaler 1024
>   OCR1A = 0x0400;                    //Zählen bis 1024;


Was den das ? Das ist kompletter müll und kein C
Die einzelnen bits kannst du nicht einfach mit nem Komma trennen.

http://www.mikrocontroller.net/articles/Bitmanipulation#Standard_C
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Ver.C3.A4ndern_von_Registerinhalten

kennst du ? Da stehts wie du Bitmanipulationen richtig machst.

von Matze (Gast)


Lesenswert?

Danke, die fehler sind nun weg.

Der Timer läuft wohl immer noch nicht, muss ich ihn irgendwie speziell 
starten?
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#define F_CPU 1000000UL    // 1 MHz (fuer delay.h)
4
#include <util/delay.h>
5
6
int main(void)
7
{
8
  PORTD = 0x00;      //Pin für Taster und ADC(Reset) als Eingang
9
  DDRD  = 0xff;
10
  PORTB = 0x00;
11
  DDRB  = 0x00;
12
  //-------TIMER-1----------------------------------
13
  TCCR1A  &= (0<<COM1A0)|(0<<COM1A1);  // CTC Modus
14
  TCCR0B &= (0<<ICNC1)|(0<<ICES1)|(0<<CS11);  // Prescaler 1024
15
  TCCR0B |= (1<<WGM12)|(1<<CS10)|(1<<CS12);  
16
  OCR1A = 0x0400;
17
  TIMSK |= (1<<OCIE1A);            //Compare Interrupt Enable
18
  sei();                    //Globale Interrupts ein
19
  //------> Timer läuft nun
20
  int lauft=0;
21
    while(1)
22
    {   
23
    lauft = TIFR&(1<<OCF1A);
24
    if(lauft)
25
    {
26
      PORTD=0x00;
27
      while(1)
28
      {
29
        ;
30
      }
31
      TIFR |= (1<<OCF1A);
32
    }
33
    else
34
    {
35
      PORTD=0x55;
36
    }      
37
    }
38
}
39
40
ISR(TIMER1_COMPA_vect) 
41
{
42
  PORTD=0x00;
43
  while(1)
44
  {
45
    ;
46
  }
47
}
Nun inst er hoffentlich auf Compare eingestellt.
Nach allem was ich gelesen habe müsste er bei einem Compare-Match das 
Bit OCF1A setzen, und einen Interrupt auslösen.

Der Interrupt soll durch
1
  TIMSK |= (1<<OCIE1A);            //Compare Interrupt Enable
2
  sei();                    //Globale Interrupts ein
ermöglicht werden.

Leider löst er nicht aus und ich kann die Minute so nicht messen.

Grüße
Matze

von Matze (Gast)


Lesenswert?

Habe den Fehler gefunden.

Ich nutze Timer 1 und stelle das Kontroll-Register von Timer 0 ein.

  TCCR1A  &= (0<<COM1A0)|(0<<COM1A1);  // CTC Modus
  TCCR1B &= (0<<ICNC1)|(0<<ICES1)|(0<<CS11);  // Prescaler 1024
  TCCR1B |= (1<<WGM12)|(1<<CS10)|(1<<CS12);

Grüße
Matze

von Peter II (Gast)


Lesenswert?

Matze schrieb:
> TCCR1A  &= (0<<COM1A0)|(0<<COM1A1);  // CTC Modus
>   TCCR1B &= (0<<ICNC1)|(0<<ICES1)|(0<<CS11);  // Prescaler 1024

das ist zwar kein fehler, aber unsinn. da kannst du auch gleich

TCCR1A  = 0;
TCCR1B  = 0;

schreiben.

von Marc (gierig) Benutzerseite


Lesenswert?

Peter II schrieb:
> as ist zwar kein fehler, aber unsinn. da kannst du auch gleich
>
> TCCR1A  = 0;
> TCCR1B  = 0;


Dann kannst du die auch gleich komplett weglassen, da nach einem Reset 
diese
IO register eh auf Null sind. (jedenfalls beim dem tiny 2313)

von Karl H. (kbuchegg)


Lesenswert?

Die while Schleife
1
ISR(TIMER1_COMPA_vect) 
2
{
3
  PORTD=0x00;
4
  while(1)
5
  {
6
    ;
7
  }
8
}
kommt da aber jetzt mal ganz schnell raus.

von Karl H. (kbuchegg)


Lesenswert?

Es ist ziemlich unwahrscheinlich, dass dein Programm ausgerechnet hier
1
    while(1)
2
    {   
3
    lauft = TIFR&(1<<OCF1A);
4
    if(lauft)
5
    {
6
      PORTD=0x00;
7
      while(1)
8
      {
9
        ;
10
      }
11
      TIFR |= (1<<OCF1A);
12
    }
13
    else
14
    {
15
      PORTD=0x55;
16
    }      
17
    }

das OCF1A Flag als gesetzt antreffen wird. Sobald es vom Timer gesetzt 
wird, erfolgt der Aufruf der ISR innerhalb der nächsten 2 bis 3 
Taktzyklen, je nachdem welchen Befehl die CPU gerade in Arbeit hat. Dann 
passieren 2 Dinge: zum einen wird dadurch genau dieses Flag sofort 
wieder gelöscht, so dass die Hauptschleife es nicht zu Gesicht kriegen 
kann und zum zweiten hältst du das Programm durch die Endlosschleife 
innerhalb der ISR fest, so dass die Hauptschleife schon alleine aus 
diesem Grund nicht weiter arbeiten kann.


Und ich seh gerade, dass du da schon wieder eine Endlosschleife 
reingeschachtelt hast. Mit Endlosschleifen scheinst du es ganz im 
Speziellen zu haben. Lass den Unsinn! Es gibt nur EINE Endlosschleife 
und das ist die eine in main()!

von Karl H. (kbuchegg)


Lesenswert?

machs doch nicht so kompliziert
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#define F_CPU 1000000UL    // 1 MHz (fuer delay.h)
4
#include <util/delay.h>
5
6
7
volatile uint8_t tick;
8
9
int main(void)
10
{
11
  PORTD = 0x00;      //Pin für Taster und ADC(Reset) als Eingang
12
  DDRD  = 0xff;
13
14
  PORTB = 0x00;
15
  DDRB  = 0x00;
16
17
  //-------TIMER-1----------------------------------
18
  TCCR1A  &= (0<<COM1A0)|(0<<COM1A1);  // CTC Modus
19
  TCCR0B &= (0<<ICNC1)|(0<<ICES1)|(0<<CS11);  // Prescaler 1024
20
  TCCR0B |= (1<<WGM12)|(1<<CS10)|(1<<CS12);  
21
  OCR1A = 0x0400;
22
  TIMSK |= (1<<OCIE1A);            //Compare Interrupt Enable
23
  sei();                    //Globale Interrupts ein
24
  //------> Timer läuft nun
25
26
  while(1)
27
  {   
28
    if( tick )
29
    {
30
      tick = 0;
31
32
      PORTD ^= 0x55;
33
    }
34
  }
35
}
36
37
ISR(TIMER1_COMPA_vect) 
38
{
39
  tick = 1;
40
}

Wenn deine Timereinstellungen stimmen, was ich nicht kontrolliert habe, 
dann müssten deine LED jetzt im Sekundentakt blinken.

von Karl H. (kbuchegg)


Lesenswert?

Wie kommst du eigentlichg auf die Idee, dass dein Programm im 1 
Sekundenrhythmus die ISR aufruft? Wenn ich nachrechne, krieg ich da aber 
was ganz anderes raus. Mal abgesehen davon, dass deine 1Mhz vom internen 
Takt keine 1Mhz sein werden und die ganze Rechnerei schon alleine 
deswegen nicht stimmt. Oder hast du einen 1Mhz QUarz am Tiny hängen?

FAQ: Timer

von Karl H. (kbuchegg)


Lesenswert?

Und ehe du da jetzt noch weiter rumhampelst:
Mal ausgehend davon, dass du den OCR1A Wert soweit korrigierst, dass du 
leidlich genau 1 Sekunden Abstände im ISR Aufruf hast, kann man Zeiten 
zb so abmessen, indem man einen Countdown-Zähler rückwärts zählen lässt, 
bis er bei 0 ist
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#define F_CPU 1000000UL    // 1 MHz (fuer delay.h)
4
#include <util/delay.h>
5
6
7
volatile uint8_t tick;
8
9
int main(void)
10
{
11
  PORTD = 0x00;      //Pin für Taster und ADC(Reset) als Eingang
12
  DDRD  = 0xff;
13
14
  PORTB = 0x00;
15
  DDRB  = 0x00;
16
17
  //-------TIMER-1----------------------------------
18
  TCCR1A  &= (0<<COM1A0)|(0<<COM1A1);  // CTC Modus
19
  TCCR0B &= (0<<ICNC1)|(0<<ICES1)|(0<<CS11);  // Prescaler 1024
20
  TCCR0B |= (1<<WGM12)|(1<<CS10)|(1<<CS12);  
21
  OCR1A = 0x0400;
22
  TIMSK |= (1<<OCIE1A);            //Compare Interrupt Enable
23
24
  sei();                    //Globale Interrupts ein
25
  //------> Timer läuft nun
26
27
  tick = 60;                // 60 Sekunden Countdown
28
29
  while(1)
30
  {   
31
    if( tick > 0 )          // läuft der Countdown noch?
32
      PORTD = 0x55;         //   Yep -> Led ein
33
    else
34
      PORTD = 0;            //   No -> Countdown ist fertig, Led aus
35
  }
36
}
37
38
ISR(TIMER1_COMPA_vect) 
39
{
40
  if( tick > 0 )
41
    tick--;
42
}

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.